Using async/await instead of the traditional promise syntax in JavaScript. Read about the TC39 proposal “top-level-await” and its criticism.

State of Async/Await in JavaScript

Asynchronous programming in JavaScript

Keerti Kotaru
Bits and Pieces
Published in
4 min readJan 25, 2022

--

In JavaScript, we use promises extensively. A promise object with an eventual result or an error, could be confusing for some who are new to the language.

iPromise_A_Response
.then(success => console.log("🥂Success 🎉")
.catch(error => console.error("💥failed🤬");
console.info("1️⃣ I evaluate before the promise results");

What is Async/Await?

Async/await in JavaScript is syntactic sugar that simplifies writing code with promises. It is a two part implementation,

async: The async keyword qualifies a function asynchronous and returns a promise. Consider the following code snippet. The function randomNumber() does NOT return a number. It returns a promise.

async function randomNumber(){ 
// Hypothetical long running function.
return Math.round(Math.random() * 10);
}

See the function call and the result below.

Async function randomNumber() returns promise.

Use the promise object returned by the function. See the output below with the promise resolved. The then() function, success callback is invoked once the promise resolved.

Promise resolved

await: It simplifies using a promise compared to the then() function syntax. Consider the following code snippet. It rewrites the above code with the await keyword.

async function callingFunction(){
rn = await randomNumber();
console.log("a random number generated,", rn);
}

Notice the second line in the code snippet. Result from the promise is assigned to a variable rn. It gives an impression of pausing the function till the promise is resolved.

However, notice, the callingFunction() is async. The async/await syntax mandates the enclosed function to be async.

In JavaScript await was always used within an async function.

In the past, the following resulted in an error:

  • If the await keyword was used in a normal function (that’s not qualified with the async keyword).
  • Outside a function, for example, in a JavaScript module .

Top level await

Through a TC39 proposal, top-level-await was introduced. With this change to the JavaScript spec, you can use the await keyword in a module, outside a function.

Consider the following snippet:

const dinoList = await import(`./${cleanupQS(location.search)}.js`);function cleanupQS(qs){
return qs.substring(1);
}
export {dinoList};

Notice the first line uses await outside a function. The resource (or the module dependency) is resolved at run time.

Use cases for top level await

  • Dynamic dependencies: As described above, the top level await allows determining module dependency at runtime. It is useful for internationalization, which loads a language file on-the-fly. It also helps identify development environment from a test environment to a production environment, depending on which determine appropriate configuration file or a JS module.
  • Initialization: Await for initialization of connections to resources like databases.
  • Configure fallbacks: Enables configuring resource-b.js if resource-a is unavailable at that time.

Footgun

The blocking nature of top level await proposal raised concerns.

Execution Order: JavaScript engines execute dependencies in post-order traversal. It starts from left most subtree, runs through all the siblings and followed by the parents till it reaches the root module (or the root node). The top level await defers current module until the promise is resolved. However, it executes the siblings without any wait (assuming they don’t have any top-level awaits). The deferred nodes and their parent nodes execute once the promises are resolved.

The footgun note raises concerns that the top-level-await blocks executing, fetching resources and interop with CommonJS module system.

Stage 3 of the TC39 proposal addressed the primary concern by supporting loading siblings, while the awaited promise is pending.

Read more about concerns and eventual consensus on the proposal here — https://gist.github.com/Rich-Harris/0b6f317657f5167663b493c722647221

Build composable web applications

Don’t build web monoliths. Use Bit to create and compose decoupled software components — in your favorite frameworks like React or Node. Build scalable frontends and backends with a powerful and enjoyable dev experience.

Bring your team to Bit Cloud to host and collaborate on components together, and greatly speed up, scale, and standardize development as a team. Start with composable frontends like a Design System or Micro Frontends, or explore the composable backend. Give it a try →

Learn More

--

--