Javascript – Why are Promises not “awaited” by default

asyncasynchronous-programmingjavascriptpromisestypescript

In the latest version of languages like TypeScript or ECMAScript you can use async/await constructs to write code that combines the clean structure of synchronous programming with the performance advantages of asynchronous code.

Take this as an example:

async function isAdmin() {
    // Async IO request...
    return false;
}

async function doSomething() {
    if (await isAdmin()) {
        console.log("Done");
    } else throw new Error("Unauthorized");
}

doSomething();

It looks very clean. However, because of the synchronous look of the code it's not that difficult to forget to await on some function invocation, thus writing things like this:

// ...
if (isAdmin()) {
    console.log("Done");
} else throw new Error("Unauthorized");

which is dangerously wrong.

What's the rationale behind this choice, instead of awaiting all async functions by default and letting the programmer choose which operation to do asynchronously? Something like this made-up syntax:

var admin = isAdmin(); // wait isAdmin to return a result
async doSomething();   // call doSomething asynchronously
doSomething();         // call doSomething synchronously
var promise = async doSomething(); // Get the underlying Promise

Best Answer

Note that a function being async doesn't turn it into something completely different, it just enables some syntax. A normal function returning a promise is just as asynchronous as a function marked with async.

  1. The await serves as a warning sign "the world may have changed in the mean time".

    await may be easier than multi threading, but it's still very error prone. During code review you have to look at each await, thinking "does the function rely on any information obtained before the await still being the same? Is this guaranteed?". Without an explicit await, you have to do so at every function invocation.

  2. Backwards compatibility. With your proposal code behaves completely different if the browse/runtime supports awaiting or not.
  3. If your code doesn't want to deal with awaiting, it needs to insert an async at every call to an externally defined function, just in case it returns a promise.
  4. Performance. The runtime needs to insert an if result is a promise then await check at every method call.