Yes, you're right. An example with a generator and promises first:
function *gen () {
const promiseValue = yield new Promise((resolve) => resolve(42));
console.log(promiseValue);
}
// .. and at some other context using '*gen'
const iterator = gen();
const { value: promise } = iterator.next(); // Promise (42)
promise.then((resolvedValue) => iterator.next(resolvedValue)); // logs 42
This generator yields a Promise
to the outside world, one whose value we pass back into the generator by passing it as an argument to the iterator.next
call, once that promise resolves.
This pattern at least intersects with what is said to be a task. The disadvantage of this is that we DO have to call next
manually on the iterator, every time a yielded promise resolves. That's where async await
comes in:
async function task() {
const promiseValue = await new Promise((resolve) => resolve(42));
console.log(promiseValue);
}
And that's all there is to it. An async function will pause until a promise expression preceded by the await
keyword resolves, and the expression will evaluate to an automatic unwrap of the promise - i.e. its final value.
Then the await expression's result (42
, in our case) will be assigned to promiseValue
, like yield
works as well. This all happens before the function continues its execution to the next statement.
This is essentially equal behaviour as the above snippet with the generator.
Although in my experience this example seems to be the most common use-case for both generators and async functions, one where async/await is definitely the cleaner approach, generators do have some really strong powers that async/await does not have in the same way (but that is another topic).
async/await
. – alexmacasync
/await
does now. I would recommend to avoid this comparison however, it should be seen as nothing but a historic artefact. I think MDN needs a good edit… – Bergi