The following implements a control flow wrapper co
enabling asynchronous code to be delineated only by the yield
keyword.
Is this basically
Stage 3 Draft / January 26, 2016
Async Functions provides examples of three patterns; Promise
; Generator
; Async Functions
; where the distinct approaches essentially produce the same result
Examples#
Take the following example, first written using Promises. This code chains a set of animations on an element, stopping when there is an exception in an animation, and returning the value produced by the final succesfully executed animation.
function chainAnimationsPromise(elem, animations) { let ret = null; let p = currentPromise; for(const anim of animations) { p = p.then(function(val) { ret = val; return anim(elem); }) } return p.catch(function(e) { /* ignore and keep going */ }).then(function() { return ret; }); }
Already with promises, the code is much improved from a straight callback style, where this sort of looping and exception handling is challenging.
Task.js and similar libraries offer a way to use generators to further simplify the code maintaining the same meaning:
function chainAnimationsGenerator(elem, animations) { return spawn(function*() { let ret = null; try { for(const anim of animations) { ret = yield anim(elem); } } catch(e) { /* ignore and keep going */ } return ret; }); }
This is a marked improvement. All of the promise boilerplate above and beyond the semantic content of the code is removed, and the body of the inner function represents user intent. However, there is an outer layer of boilerplate to wrap the code in an additional generator function and pass it to a library to convert to a promise. This layer needs to be repeated in every function that uses this mechanism to produce a promise. This is so common in typical async Javascript code, that there is value in removing the need for the remaining boilerplate.
With async functions, all the remaining boilerplate is removed, leaving only the semantically meaningful code in the program text:
async function chainAnimationsAsync(elem, animations) { let ret = null; try { for(const anim of animations) { ret = await anim(elem); } } catch(e) { /* ignore and keep going */ } return ret; }
Is this basically what async/await does under the hood in ESwhatever?
Not really. It's a different approach for doing sorta the same thing. What async/await
turn into is more like
async function foo() {
const bar = await Bar();
bar++;
const baz = await Baz(bar);
return baz;
}
becomes
function foo() {
return Bar()
.then(bar => {
bar++;
return Baz(bar)
.then(baz => {
return baz;
});
});
}