liveBook · Manning

Async/await

As explained in The Joy of JavaScript

An async function is a JavaScript function that returns a Promise and can suspend execution while awaiting asynchronous work.

async/await gives Promise-based work the shape of ordinary, step-by-step JavaScript. An async function returns a Promise; inside it, await lets the next statement use an asynchronous result as a local value. The code looks as if it pauses, but Promises and the event loop still handle the work. section 8.4 section 1.5

Use it when a task has dependent steps: check access to a file, read it, transform its contents, then return a result. A Promise chain expresses the same flow with successive then calls. async/await separates those calls into statements without changing the underlying Promise-based behavior; callers can still use then on the returned Promise. section 8.4

To turn a Promise chain into an async function:

  • Add async to the function declaration so callers know it returns a Promise. section 8.4
  • Replace each then step with an awaited result and an explicit local variable where the next step needs that value. section 8.4
  • Move catch logic into a try/catch around the asynchronous steps. section 8.4
Listing 8.21 Using async/await to count blocks in blocks.txt
const fsp = fs.promises;
 
async function countBlocksInFile(file) {                                #1
   try {
      await fsp.access(file, fs.constants.F_OK | fs.constants.R_OK);    #2
      const data = await fsp.readFile(file);                            #3
      const decodedData = decode('utf8', data);
      const blocks = tokenize(';', decodedData);
      return count(blocks);  
   }
   catch(e) {                                                           #4
      throw new Error(`File ${file} does not exist or you have 
         no read permissions. Details: ${e.message}`);
   }   
}
 
const result = await countBlocksInFile('blocks.txt'); 
result; // 3

The file example makes the conversion concrete: await checks access and reads the file, ordinary functions transform its contents, and try/catch supplies an error message. section 8.4

await normally belongs inside an async function. Top-level await is the exception for ECMAScript Modules: a module can await startup work, such as a dynamic import, without wrapping it in an immediately invoked async function. A module that imports it waits for that work to finish, so consider the effect of awaiting during module initialization. section 8.6 section 8.7

How The Joy of JavaScript covers it

How deep it goes
Works through a chain-to-async refactor, including awaited locals and try/catch, and explains top-level module behavior without detailing module evaluation internals.
Examples
Shows file access and reading before counting blocks, plus dynamic imports during module startup.
What it assumes
Assumes familiarity with callbacks and builds on Promise chains; teaches the async/await conversion explicitly.
What you can do after
Build it from scratch by refactoring a Promise chain into an async function, then consume its result with await or then.
How it connects
Connects Promises, the event loop, error handling, dynamic imports, and ECMAScript Modules.

Also explained in

Compare how 17 books explain async/await →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Joy of JavaScript. The section links point to the parts of the book it draws on.