Revisiting this after a few years, the await.all
proposal feels kinda footgunny (everything runs in parallel inside the brackets??) A better solution would probably look more like async do
block (maybe with even fewer brackets though?) A few ideas:
Bracketless async do expresisons
Bracketless async do expresisons are a more generally-useful syntax and parts of it already have community support. The likeliest route to success is probably just to support this feature-set on those proposals
async function initialize() {
await Promise.all([
async do let foo = (await request('foo.json')).data,
async do let bar = (await request('bar.json')).data,
async do let baz = (await request('baz.json')).data,
]);
render(foo, bar, baz);
}
async do let
is so verbose omg, it feels like casting a spell. But it's 8 fewer brackets than the equivalent IIAFE AND saves us from having to do a separate declaration step!
There's an open bug in the do-expressions proposal regarding bracketless-do. It looks like it'd cause all sorts of operator precedence confusion: tc39/proposal-do-expressions#1 -- There's been no movement on this since August 2021 but the conversation doesn't look like it's come to a clear conclusion either
Someone in that bug already made note of the scope thing but I don't think they realized the potential power of what they were saying: tc39/proposal-do-expressions#1 (comment)
Async do expressions haven't seen any action since Feb 2021, but there's now a standalone proposal for them
defer Expression
This is a similar feature inspired by the IcedCoffeeScript keyword mentioned in the Prior Art section of the proposal.
Transpilation: defer Expression
-> (async () => Expression)()
(may require curlies around arrow function body? idk)
async function initialize() {
let foo, bar, baz;
await Promise.all([
defer foo = (await request('foo.json')).data,
defer bar = (await request('bar.json')).data,
defer baz = (await request('baz.json')).data,
]);
render(foo, bar, baz);
}
defer Ident = Expression
It would be even more convenient if it somehow also handled declaration in the surrounding scope?
Transpilation A: defer Ident = Expression
->
/* injected before current statement: */ let Ident;
/* inline: */ (async () => { Ident = Expression })()
Transpilation B: defer Ident = Expression
-> (do { var Ident; }, (async () => { Ident = Expression })())
async function initialize() {
await Promise.all([
defer foo = (await request('foo.json')).data,
defer bar = (await request('bar.json')).data,
defer baz = (await request('baz.json')).data,
]);
render(foo, bar, baz);
}