async/await -> await/async: a simpler, less error-prone async syntax

Steven Mascaro subs at
Mon Dec 4 12:52:48 UTC 2017

Thanks Naveen, I agree, potentially in full.

Let me address T.J. Crowder's objections out of order (2,3,1), as the
response will be clearer that way.

2. As Naveen noted, this is a use case that I did (and very much intended
to) handle in the proposal by having a keyword at the call site. Namely:
`let promise = async remote.runInBackground();`.

3. I think the principle "prefer explicit to implicit" argues in *favour*
of the proposal (and against the existing syntax). You gave the example:

let x = foo();
let y = bar();

Imperative language conventions imply the second statement only executes
after the first is fully complete. But if `foo` and `bar` are defined as
async functions, the second statement likely starts executing before the
*real* work being done in the first statement is complete. The proposed
syntax restores the normal imperative conventions, and requires one to be
explicit when code departs from those conventions. e.g.:

let p = async baz(); // We're explicit that this doesn't work like every
other sync function, it just returns a promise!
let x = foo(); // This could be an await function or an ordinary sync
function. We don't need to care (outside of atomics,etc.)
let y = bar(x); // Ditto

If you're really committed to being explicit, then we should require the
coder to specify how they want *every* call to an async function to be
handled. e.g.:

let p = async baz(); // Explicit
let x = await foo(); // Explicit
let y = await bar(x); // Explicit

But this seems needlessly verbose.

1. I'm not committed to keeping the `async` and `await` keywords. My
original thoughts on this were much like Naveen's proposed keywords. I was
initially using `awaitalways` for `await` in the function declaration and
`trap` for `async` at the call site, but if we do want to use different
keywords, I think I prefer `awaitauto` and `background`. (`awaitauto`
rather than `asyncauto` because I think it's very important to be clear
about what the default call behaviour becomes.)

However, I later realised that the keyword reuse will only be confusing to
someone who has only learned the existing (essentially incomplete)
async/await syntax. Someone entirely *new* to the language may actually
find the completed symmetry of the proposal *less* confusing. The
explanation for a new JS developer might run as follows:

*Asynchronous Functions*
An "asynchronous function" is any function that returns a `Promise`.

`async` and `await` control how an asynchronous function is executed.
Prefixing a call to an asynchronous function with `async` will cause it to
be run in an asynchronous thread, and will return the `Promise`. Prefixing
a function call with `await` will cause execution of the current function
to be suspended until the asynchronous function has completed (successfully
or otherwise), potentially returning a value computed by the function.
Specifying how asynchronous functions should be called every time is
cumbersome and error-prone, so you can specify the default approach to
calling the function in the function declaration. Thus:

async function foo() {}

specifies that all calls to the function `foo` will use the `async` method
by default and

await function bar() {}

specifies that all calls to the function `bar` will use the `await` method
by default. In either case, you can override the default and force the call
behaviour by prefixing the call with either `await` or `async`.

And I think this possibly makes things far clearer than any description
I've yet seen, not because it was especially eloquent, but simply because
the missing pieces have now been filled in.

Nonetheless, I could be convinced otherwise, and I'd be more than willing
to accept Naveen's suggestions for different keywords.


On 4 December 2017 at 16:38, Naveen Chawla <naveen.chwl at> wrote:

> The crux of your idea is: let any calls of an async function inside an
> async function automatically await unless explicity instructed to run "in
> the background". I like the idea. I just wouldn't use the words "await" and
> "async" for it, because they are used as currently in C#.
> On the last disagreement by T.J Crowder: 1. it's an alternative (perhaps
> with different words), not necessarily in conjunction with the existing
> syntax. 2. The promise would be accessible via e.g. `const promise = background
> remote.runInBackground();` 3. If a presumption is made that in an async
> function, other async function calls are automatically awaited unless
> prefixed with `background`, I'm not sure about the value of having a "clear
> indicator" of which function calls are sync and which are async - in normal
> use I wouldn't care. I just want their results and if I want to make a
> function async (by adding a server call, etc.), I can do so transparently
> without breaking my code. I agree with the thrust of this proposal.
> The horse has bolted on `await` `async`, but maybe with different
> keywords, e.g. `asyncauto` and `background`, I would definitely use this
> new syntax instead of `await` `async` (which I use currently), for the
> reasons stated in the original post. Bug minimization is a big factor in
> the features I use, and should be THE driving factor in introducing new
> features.
> The OP has stated this idea upon extensive real world use, and I
> appreciate that. I would definitely support the introduction of e.g.
> `asyncauto` and `background`, and would definitely use it immediately in
> all cases instead of `async` `await` if introduced.
> On Sun, 3 Dec 2017 at 17:13 T.J. Crowder <tj.crowder at>
> wrote:
>> I understand the motivation, but I have to disagree with the proposal
>> for multiple reasons:
>> 1. It adds too much confusion to the existing syntax.
>> 2. If the calling code needs to call one of these new-style `await`
>> functions and access its promise (rather than `await`ing it), it
>> doesn't have a way to do that; `async`/`await` doesn't have full
>> coverage of all patterns (yet, possibly never), sometimes you still
>> need to access the actual promise (for instance, to feed into
>> `Promise.all` or `Promise.race`). (Obviously you could add something
>> to make it possible to access the promise.)
>> 3. Having a clear indicator in the source saying where the async
>> boundaries are is useful for code correctness. With the new syntax, I
>> have no idea of the temporal sequence of this code:
>> ```js
>> let x = foo();
>> let y = bar();
>> ```
>> ...without going and looking at the declarations of `foo` and `bar`.
>> With current syntax, it's clear when there's an async break in the
>> flow. I think the phrase is "prefer explicit to implicit" or something
>> like that.
>> -- T.J. Crowder
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list