i.e.:
async function () { ... }
// or
async () => { ... }Note that that explanation was purposefully ignoring any implementation details about whether or not closures are actually being created/allocated and was purely focusing on whether the programmer had to type out/read closures as extra syntax.
Actually, functional programmers might point out that even without async/await, assignment in imperative languages is still just some syntactic sugar for actually using closures. That is, in functional languages, its almost never idiomatic to directly "assign" to a variable (that is, overwriting the variable's previous value); instead values are "bound" to variables in let statements (or whatever the language's idiomatic equivalent is)--and let statements are effectively syntactic sugar for function calls/closures.
If you're familiar with haskell: you can think of imperative code as haskell's do notation but with the Identity macro (aka no special mode of computation, just the results of each function flowing into the next with "assignment" converted into functions). Marking a function as async (and thus allowing you use to await inside it) is just switching that function to be under the Promise monad. (but be careful! JavaScript promises aren't strictly monadic in that they auto-resolve if nested... so you can't have "Promise Promise a")
(... Sorry, this ended up being a bit of a mess of a braindump because you specified "implicit" closures :) )
1. It allows you to reason linearly about code with IO mixed in, without blocking the entire event loop. This is incredibly useful. Computer programmers are very good at reasoning linearly. It is just much, much more comfortable [1] to think about code that uses async/await than the same code with promises.
2. I think the way that promises and async/await interop is very beautifully designed. The way it ends up working in practice is that you can write a function that "blocks"[2], but if you later decide you want to call it in parallel with something else, that's fine because async functions are just a thin wrapper around Promises. So you can just take that existing function and call `Promise.all()` on it. Similarly if you start with a function that returns a promise, and you decide you want to call it in a blocking way -- you just do `await thingThatReturnsPromise()`. This is an almost perfect example of primitives composing to be more than the sum of their parts.
3. (and this is worth the price of admission alone) error handling works properly and automatically. If you `await` an async function and it throws, you'll get a plain ol' JavaScript error thrown which you catch in the normal way. If I never debug another hung JavaScript app that dropped a rejected promise on the floor it will be too soon.
[1] please don't tell me that I just don't "get" asynchronous programming. I was writing js event handlers when you were in diapers (something something lawn something).
[2] `await` doesn't really block the event loop, it just appears to.
This sounds pretentious and detracts from an otherwise good comment, even if you didn’t mean it to.
Makes writing correct code easier.
With async/await the language takes care of lowering those control structures that straddle async operations, similarly a compiler lowering them into conditional branch instructions.
However if you have control flow in it (execute this async function 100 times, add the results, depending on the result call another async function, ...) things will get a lot more ugly with raw promises.
Allowing programmers to write code as if it was synchronous removes a lot of confusion, boilerplate, and bugs.
Nothing was impossible. Maybe if you had 3+ levels of nested Ajax calls then it needed bit of head scratching, but jQuery's Deferred and other promise libraries are pretty neat to solve these issues.
However this could be indeed hidden from the programmer.
Look, I get its use case. It simplifies doing asynchronous and synchronous programming together. It takes an asynchronous operation and turns it into synchronous which worries me a bit about new developers and code readability. There are APIs including parts of node, HTML 5, etc that async and await isn't going to work with. So now you're going to have normal synchronous code, asynchronous code that looks synchronous, and other asynchronous code that can't be made to look synchronous.
I'm all for finding ways to avoid callback soup and to simplify asynchronous patterns. I think there are good ways to structure traditional callbacks that is sane and I think promises are a great step. I'm skeptical about async and await.
XMLHttpRequest was enhanced with the Fetch API which uses promises. The libraries and methods will eventually catch up in a similar way.
If we stopped here there'd be little reason to ask everyone to promisify their libraries. The promise callback chain was only slightly more easy to read than the callback pyramid of doom. You might say that async/await lowers the explicit complexity vastly and increases the implicit complexity marginally.
Too bad promises had a lot of glaring flaws that are taking forever to fix (or are unfixable). We're just getting to the point where unhandled errors are dealt with properly. Composing promises with non-promise constructs still suck. There's still only 2 paths (success and error). The flatMapLatest scenario still suck.
Still, promises were the improvement. Async/await is just sugar.
This is just pointless syntax.