Search Knowledge

© 2026 LIBREUNI PROJECT

Modern JavaScript & Ecosystem / Asynchronous JavaScript

Async/Await: Syntactic Asynchrony

Bridging the Gap

While Promises were a massive improvement over callbacks, chaining many .then() calls can still lead to complex logic flows. ECMAScript 2017 introduced async and await, which act as syntactic sugar over Promises. They allow developers to write asynchronous code that looks and behaves more like traditional synchronous code, making it easier to read and debug.

The async Keyword

By prefixing a function with the async keyword, you guarantee that the function will always return a Promise.

  • If the function returns a non-promise value, that value is wrapped in a resolved Promise.
  • If the function throws an error, the returned Promise is rejected with that error.

The await Operator

The await keyword can only be used inside an async function (or at the top level of an ES module). It pauses the execution of the async function until the Promise it is waiting for settles.

Importantly, await does not block the main thread. It only pauses the execution of the specific async function, allowing the Event Loop to continue processing other tasks.

javascript
1async function getAtmosphereData() {
2 console.log("Initiating request...");
3
4 // Simulated network delay using a Promise
5 const telemetry = await new Promise(res =>
6 setTimeout(() => res({ oxygen: 21, nitrogen: 78 }), 1000)
7 );
8 
9 console.log("Data received:", telemetry);
10 return telemetry.oxygen;
11}
12 
13getAtmosphereData().then(o2 => console.log("O2 level:", o2));

Error Handling with Try/Catch

One of the greatest benefits of async/await is that it allows the use of standard try/catch/finally blocks for error management, consolidating asynchronous and synchronous error handling into a single pattern.

async function uploadLogs(logs) {
  try {
    const response = await api.post('/logs', logs);
    return response.status;
  } catch (error) {
    console.error("Upload failed:", error.message);
    throw new Error("System failure during upload");
  } finally {
    clearBuffer();
  }
}

The “Sequential” Trap

A common mistake when using async/await is accidentally making independent asynchronous operations sequential, which increases the total execution time.

javascript
1async function parallelFetch() {
2 const p1 = fetch('https://api.test/1');
3 const p2 = fetch('https://api.test/2');
4 
5 // Using await on both separately but starting them together
6 // or using Promise.all is preferred
7 const [r1, r2] = await Promise.all([p1, p2]);
8 return [r1, r2];
9}

What happens if you use 'await' on a value that is NOT a Promise?

Implementation Detail: Generators and Iterators

Under the hood, async/await is typically implemented using Generators and yield. An async function is essentially a generator function that is automatically stepped forward by a runner (like the co library used to do) whenever a yielded promise resolves. This allows the function to “pause” its state (local variables, execution point) and resume exactly where it left off, all without blocking the system.