It has been postulated (with sound reasoning) that top level await is a bad idea.
If so, are there any advantages to having await at all, when we already have yield.
Having async is useful because an async function is guaranteed to return a promise irrespective of what is actually returned by the code. But do have some similar reasoning behind await as well ?
So after some introspection and exploration, the answer is somewhat obvious.
When using generators it is the application developer's responsibility to pass the generator to the runner (eg. co). Async/await can be thought of as a higher level abstraction than can build upon this to make this implicit and remove the responsibility from application developer's hands.
Whenever we await inside an async function, the runtime ensures that we either get back a resolved value or fail with an exception.
Plus, similar to async function always return a promise irrespectively what the code returns, await can handle things that are not promises (by effectively calling Promise.resolve).
This makes async await more obvious choice for asynchronous control flow and generators for their intended use case - building iterators. This intent is also supported by the upcoming TC39 async-iteration proposal (with a regenerator polyfill) that further extends these ideas to support asynchronous iterators:
async function* iterator(arg) { .... }
Async generator functions are similar to generator functions, with the following differences:
- When called, async generator functions return an object, an async generator whose methods (next, throw, and return) return promises for { next, done }, instead of directly returning { next, done }. This automatically makes the returned async generator objects async iterators.
- await expressions and for-await-of statements are allowed.
- The behavior of yield* is modified to support delegation to async iterables.
async function* readLines(path) {
let file = await fileOpen(path);
try {
while (!file.EOF) {
yield await file.readLine();
}
} finally {
await file.close();
}
}
This makes the usage scenarios explicit and makes interoperability seamless.
Denny Trebbin
Lead Fullstack Developer. Experimenting with bleeding-edge tech. Irregularly DJ. Hobby drone pilot. Amateur photographer.
When @sandeep calls, I follow ;-)
Rich Harris's Gist-Blog post drew some attention :-)
What is
asyncandawait?async/awaitis syntactical sugar on top of generator functions which yield Promises. Personally, I don't like the generator syntax; that's why I sparingly write any code like thisfunction* fn() { yield maybe.something() }.So I think
asyncandawaitare excellent additions but as Rich Harris pointed out, the parser and code generators must do much better or only restrict its usage or use cases.The more I think about it, the less I need
asyncandawait. Most of my problems are gone when we have widely accessible cancellable Promises. That would solve more of my code smell. Because who expects a Promise when one defines anasync function() {whichawait maybe.something() }. I opened more questions then I answered, sorry ;-)