Async Functions internally leverage both generators and promises:
asyncfunctionexample(a, b, c) {/* example function body */}// is compiled into...functionexample(a, b, c) {returnspawn(function*() {/* example function body */ },this);}
In spawn, a promise is wrapped around code that will step through the generator function – made out of user code – in series, forwarding values to your “generator” code (the async function’s body).
In this sense, we can observe that Async Functions really are syntactic sugar on top of generators and promises, which makes it important that you understand how each of these things work in order to get a better understanding into how you can mix, match, and combine these different flavors of asynchronous code flows together.
functionspawn(genF, self) {returnnewPromise((resolve, reject) => {constgen=genF.call(self);step(() =>gen.next(undefined));functionstep(nextF) {let next;try { next =nextF(); } catch (e) {// finished with failure, reject the promisereject(e);return; }if (next.done) {// finished with success, resolve the promiseresolve(next.value);return; }// not finished, chain off the yielded promise and `step` againPromise.resolve(next.value).then( v =>step(() =>gen.next(v)), e =>step(() =>gen.throw(e)) ); } });}
When the sequence is over or one of the promises is rejected, the promise returned by the underlying generator function is settled.