What is this syntax in ES6 or ES7? - ecmascript-6

I came across this syntax which I believe is ES6 or ES7. What do these lines of code do?
module.exports = async (taskData) => {
// do stuff
}

It exports an asynchronous arrow function which takes in an argument taskData. The asynchronous function is new syntax that is set to come with this year's release, ES2017, called the async function, though the rest of the code is ES6 (ES2015) and ES5 (ES2011). It goes hand-in-hand with await and returns a Promise.
It's primarily useful to clean up promise chains, where the code can get really messy. Consider this example using promises, found here:
function loadStory() {
return getJSON('story.json').then(function(story) {
addHtmlToPage(story.heading);
return story.chapterURLs.map(getJSON)
.reduce(function(chain, chapterPromise) {
return chain.then(function() {
return chapterPromise;
}).then(function(chapter) {
addHtmlToPage(chapter.html);
});
}, Promise.resolve());
}).then(function() {
addTextToPage("All done");
}).catch(function(err) {
addTextToPage("Argh, broken: " + err.message);
}).then(function() {
document.querySelector('.spinner').style.display = 'none';
});
}
The example above fetches a story, and iterates through all the chapters and adds them to the HTML. It works, but it can be very messy and hard to follow if you've got lots of stuff to do. Instead, you can use async and await, which is just syntactic sugar, but makes it much more clean:
async function loadStory() {
try {
let story = await getJSON('story.json');
addHtmlToPage(story.heading);
for (let chapter of story.chapterURLs.map(getJSON)) {
addHtmlToPage((await chapter).html);
}
addTextToPage("All done");
} catch (err) {
addTextToPage("Argh, broken: " + err.message);
}
document.querySelector('.spinner').style.display = 'none';
}
The above is (in my opinion) way more clean and easy to follow, versus the messy promise chain in the first example.

This is an async function which is set to return Promise as #Andrew says.
It is using Arrow Function syntax.
()=>{}
This function is in ES6 and does not define its own this context and any use of this will refer to the outer scope.

Async await syntax is set to be supported when ES2017 is released. Your code is essentially a function that returns a promise. Additionally, the async keyword allows for syntactic sugar when working with promises by use of the await keyword.
The => part is called an arrow function which again is a syntactic sugar for the most part. It is part of ES6.
Your function
module.exports = async (taskData) => {
// do stuff
}
... is almost the same as:
module.exports = function(taskData) {
return new Promise(function() {
// do stuff
if (err) reject(err)
resolve(your return value)
}
}
Note: the main difference is just the binding of the this keyword via the arrow function.

Related

Angular - How to set up a parallel for loop in event binding function?

I have a function that expands every RowCol object in a FlexGridDetailProvider upon click. Right now, performance is bad with the way data binding works on FlexGrid rows, so I'm looking to improve performance by parallelizing each statement in the for loop.
Here's the typescript function:
if (thisDetailProvider!= null) {
setTimeout(() => {
try {
for (var t = 0; t < grid.rows.length; t++) {
if (thisDetailProvider.isDetailAvailable(t)) {
thisDetailProvider.showDetail(t);
this.gridSelectionService.clearSelectionFromGrids(thisDetailProvider.grid);
}
}
} catch (err) { console.log(err); }
}, 100);
}
I'd like the solution to be as simple as using the Parallel.For loop provided with C#. The solutions I've found so far require turning the event binding function into an asynchronous function, but I'd like to avoid introducing that complexity if there is a simpler way.
You can use async function to achieve the reduced code complexity. It is same as promise.
// `async` function | define a function start with `async` keyword
async myAsyncFunc() {
// #1 `async` ensures that the function returns a promise,
// even without explicitly return
return 123;
// #2 we can also `explicitly` return a promise
// this works same as above return
// return Promise.resolve(123);
// we can do both the ways but
// as `async` ensures that the function returns a promise
// so why to write extra code to return explicitly
}
// calling a function - and to get return result call then()
// the function inside then() will return the value
myAsyncFunc().then((returnVal) => {
console.log(returnVal); // 123
});
async yourFunction(){
for (var t = 0; t < grid.rows.length; t++) {
if (thisDetailProvider.isDetailAvailable(t)) {
thisDetailProvider.showDetail(t);
this.gridSelectionService.clearSelectionFromGrids(thisDetailProvider.grid);
}
}
}
In your case, I guess you can ignore the returning part which involves then

How do I use promises in a Chrome extension?

What I am trying to do is create a chrome extension that creates new, nested, bookmark folders, using promises.
The function to do this is chrome.bookmarks.create(). However I cannot just
loop this function, because chrome.bookmarks.create is asynchronous. I need to wait until the folder is created, and get its new ID, before going on to its children.
Promises seem to be the way to go. Unfortunately I cannot find a minimal working example using an asynchronous call with its own callback like chrome.bookmarks.create.
I have read some tutorials 1, 2, 3, 4. I have searched stackOverflow but all the questions do not seem to be about plain vanilla promises with the chrome extension library.
I do not want to use a plugin or library: no node.js or jquery or Q or whatever.
I have tried following the examples in the tutorials but many things do not make sense. For example, the tutorial states:
The promise constructor takes one argument—a callback with two
parameters: resolve and reject.
But then I see examples like this:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
How this works is a mystery to me.
Also, how can you call resolve() when its never been defined? No example in the tutorials seem to match real life code. Another example is:
function isUserTooYoung(id) {
return openDatabase() // returns a promise
.then(function(col) {return find(col, {'id': id});})
How do I pass in col, or get any results!
So if anyone can give me a minimal working example of promises with an asynchronous function with its own callback, it would be greatly appreciated.
SO wants code, so here is my non-working attempt:
//loop through all
function createBookmarks(nodes, parentid){
var jlen = nodes.length;
var i;
var node;
for(var i = 0; i < nodes.length; i++){
var node = nodes[i];
createBookmark(node, parentid);
}
}
//singular create
function createBookmark(node, parentid){
var bookmark = {
parentId : parentid,
index : node['index'],
title : node['title'],
url : node['url']
}
var callback = function(result){
console.log("creation callback happened.");
return result.id; //pass ID to the callback, too
}
var promise = new Promise(function(resolve, reject) {
var newid = chrome.bookmarks.create(bookmark, callback)
if (newid){
console.log("Creating children with new id: " + newid);
resolve( createBookmarks(bookmark.children, newid));
}
});
}
//allnodes already exists
createBookmarks(allnodes[0],"0");
Just doesn't work. The result from the callback is always undefined, which it should be, and I do not see how a promise object changes anything. I am equally mystified when I try to use promise.then().
var newid = promise.then( //wait for a response?
function(result){
return chrome.bookmarks.create(bookmark, callback);
}
).catch(function(error){
console.log("error " + error);
});
if (node.children) createBookmarks(node.children, newid);
Again, newid is always undefined, because of course bookmarks.create() is asynchronous.
Thank you for any help you can offer.
Honestly, you should just use the web extension polyfill. Manually promisifying the chrome APIs is a waste of time and error prone.
If you're absolutely insistent, this is an example of how you'd promisify chrome.bookmarks.create. For other chrome.* APIs, you also have to reject the callback's error argument.
function createBookmark(bookmark) {
return new Promise(function(resolve, reject) {
try {
chrome.bookmarks.create(bookmark, function (result) {
if (chrome.runtime.lastError) reject(chrome.runtime.lastError)
else resolve(result)
})
} catch (error) {
reject(error)
}
})
}
createBookmark({})
.then(function (result) {
console.log(result)
}).catch(function (error) {
console.log(error)
})
To create multiple bookmarks, you could then:
function createBookmarks(bookmarks) {
return Promise.all(
bookmarks.map(function (bookmark) {
return createBookmark(bookmark)
})
)
}
createBookmarks([{}, {}, {}, {}])
.catch(function (error) {
console.log(error)
})
Take the advantage of the convention that the callback function always be the last argument, I use a simple helper function to promisify the chrome API:
function toPromise(api) {
return (...args) => {
return new Promise((resolve) => {
api(...args, resolve);
});
};
}
and use it like:
toPromise(chrome.bookmarks.create)(bookmark).then(...);
In my use case, it just works most of the time.

How can i convert typescript callback to promise

i want to make a method in my class. This method should connect to a MySQL database. I created my SQL code. And now I don't want to do a callback because this is old, I want to start using promises.
My function with callback (old school):
public does_player_exist(username: string, callback: any) {
this.mysql.connect();
this.mysql.query('USE devdb');
this.mysql.query('SELECT p_name FROM players WHERE p_name = "'+username+'"', (err: Error, result: any[]) {
if (result.length === 1) {
callback(true)
} else {
callback(false);
}
});
}
And here follows the method I tried to make a promise, but I failed:
public does_player_exist(username: string): Promise<boolean> {
this.mysql.connect();
this.mysql.query('USE devdb');
return this.mysql.query('SELECT p_name FROM players WHERE p_name = "'+username+'").toPromise().then((result) => {
return result.length === 1;
})
}
When I call this method:
service.does_player_exist('test').then((result) => { console.log(result) })
I hope someone can help me. Because I really don't want to be old school forever xD
Thanks in advance.
create a new Promise and resolve it / reject it in the callback functions of query. then return the promise. now does_player_exist returns a Promise object which contains for example then function
public does_player_exist(username: string, callback: any): Promise<boolean> {
this.mysql.connect();
this.mysql.query('USE devdb');
var promise = new Promise<boolean>();
this.mysql.query('SELECT p_name FROM players WHERE p_name = "'+username+'"', (err: Error, result: any[]) {
if (!err) promise.resolve(!!result.length);
else promise.reject();
});
return promise;
}
you will have to make sure that you have a Promise class available. that depends on your environment.
please be aware that without sanitizing your input (username) your application will be vulnerable and attackers could hijack your app.
Tip #1. Please use some kind of factory function to build your connection and reuse it later on.
Tip #2. Use prepared statement to prevent SQL injection.
Tip #3. Please use some promise library for that like Bluebird or Q. Most of the 3rd party promise libraries have a lot of useful utility methods to work with promises on of them is promisify. Promisify can wrap any nodejs type callback function into function which returns a promise.
Your example would look like:
// it's not a factory function*
public query() {
this.mysql.connect();
this.mysql.query('USE devdb');
return Promise.promisify(this.mysql.query.bind(this.mysql))
}
public does_player_exist(username: string): Promise<boolean> {
return this
.query('SELECT p_name FROM players WHERE p_name = ?', [username])
.then(result => result.length === 1);
}
I wrote a simple npm package to do this in a way that retains type-safety:
ts-promisify-callback
It requires you use typescript#^4.0 (upcoming release) and currently only works for callbacks in the popular format of (err, result) => {}.

Why does Promisification fail for some methods but not all?

The jsonix library does not follow the first argument must be an error convention so I decided to use bluebird and promisify it like so:
return new Promise(function(resolve, reject) {
try {
unmarshaller.unmarshalString(xmlResponse,
function (unmarshalled) {
...
resolve(unmarshalled);
});
}
catch (error) {
reject(error);
}
});
But this hangs indefinitely! Whereas if I simply save the xmlResponse to a file and then process it with a different method: unmarshalFile ... the promisification seems to work just fine!
return new Promise(function(resolve, reject) {
try {
unmarshaller.unmarshalFile('test1.xml',
function (unmarshalled) {
...
resolve(unmarshalled);
});
}
catch (error) {
reject(error);
}
});
So my question is why would promisification fail for one method but not another?
When I look at the code for jsonix, I don't see any callback function for .unmarshalString() and looking at the implementation, there's nothing async in the implementation and nothing that calls a callback. It just returns the answer directly. So, the function is synchronous, not async and returns its value directly as a return value.
For reference, .unmarshalURL() and .unmarshalFile() do accept the callback and do have an async implementation - .unmarshalString() is just different.
So, you don't need to use promises with unmarshaller.unmarshalString(xmlResponse) at all. You could just return the straight value:
return unmarshaller.unmarshalString(xmlResponse);
If you want to wrap it in a promise for consistency of interface among all three methods, you can do this:
try {
return Promise.resolve(unmarshaller.unmarshalString(xmlResponse));
} catch(err) {
return Promise.reject(err);
}
Or, you can use Bluebird's Promise.method() to wrap it for you:
return Promise.method(unmarshaller.unmarshalString.bind(unmarshaller, xmlResponse));
Disclaimer: I'm the author of Jsonix.
unmarshalURL and unmarshalFile are async (and have to be) but unmarshalString or unmarshalDocument are not async (and don't have to be).

Yielding streams in generator functions

I have recently started using Q.spawn function to run generators that yield promises. This works well in browsers where the support for streams is yet to land but in case of node we have streams. If you're using streams inside a generator function and would like to yield once writer stream is done then your code becomes not so clean.
Q.spawn(function* () {
yield new Promise(resolve => {
let fromStream = fs.createReadStream('x.txt');
let toStream = fs.createWriteStream('y.txt');
toStream.on('end', () => resolve());
fromStream.pipe(toStream);
});
});
It works but as soon as I start dealing with a lot streams the code becomes really ugly. Can this be made as simple as following snippet?.
someGeneratorFuncRunner(function* () {
yield fs.createReadStream('x.txt')
.pipe(fs.createWriteStream('y.txt'));
});
You don't need to put most of that code inside the Promise constructor:
Q.spawn(function* () {
let fromStream = fs.createReadStream('x.txt');
let toStream = fs.createWriteStream('y.txt');
fromStream.pipe(toStream);
yield new Promise(resolve => {
toStream.on('end', resolve);
});
});
And of course if you're waiting for lots of streams, it would make sense to factor out the promise constructor call into a helper function:
function endOf(stream) {
return new Promise(resolve => {
stream.on('end', resolve);
});
}