async/await in JavaScript
async/await in JavaScript
~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
async/await is "syntactic sugar" over promises (chapter 24) – EXACTLY the same functionality, but in a syntax that reads like SYNCHRONOUS code. Let's build our budget app's final file-loading system with it.
The async function
async before a function does two things: the function ALWAYS returns a promise (even if no promise is mentioned in the body), and await may be used inside it.
import { readFile } from 'node:fs/promises'; // the promise-based variant of fs!
async function loadTransactions(path) {
const content = await readFile(path, 'utf-8'); // 'pauses' HERE until the promise resolves
return JSON.parse(content);
}
console.log(typeof loadTransactions('transactions.json')); // Wrong! Not awaited - see belownode:fs/promises is a promise-based variant of the fs module (as opposed to the callback version from chapter 24) – the standard way to do file operations in modern async/await code.
await is only allowed inside async functions
async function process() {
const transactions = await loadTransactions('transactions.json');
console.log(`${transactions.length} transactions loaded`);
return transactions;
}
process(); // itself returns a promise again - see the next sectionawait ONLY "pauses" the current async function – the rest of the program keeps running, EXACTLY as explained in chapter 23 (the event loop knowledge from there still applies unchanged, only the syntax has changed).
Using an async function's result
Since loadTransactions itself returns a promise, there are two valid ways to get at the result:
// Way 1: .then() (from chapter 24, still works identically)
loadTransactions('transactions.json').then(transactions => {
console.log(transactions.length);
});
// Way 2: await, from within ANOTHER async function
async function main() {
const transactions = await loadTransactions('transactions.json');
console.log(transactions.length);
}
main();Multiple await calls: sequential vs. parallel
A common performance mistake: several INDEPENDENT await calls one after another, instead of running them in parallel:
// Slow - sequential, each waits for the previous one (total time: sum of all three):
async function loadAllSlower() {
const january = await loadTransactions('january.json');
const february = await loadTransactions('february.json');
const march = await loadTransactions('march.json');
return [january, february, march];
}
// Fast - parallel, all three start at once (total time: the SLOWEST one's time):
async function loadAllFaster() {
return Promise.all([
loadTransactions('january.json'),
loadTransactions('february.json'),
loadTransactions('march.json'),
]);
}Tipp: Rule of thumb: if the await calls DEPEND on each other (call 2 needs call 1's result), sequential waiting is REQUIRED. If they're INDEPENDENT, Promise.all() followed by a single await is almost always faster.
Top-level await
In ES modules (chapter 21), await may also appear OUTSIDE an async function, directly at the top level of a file:
import { loadTransactions } from './fileStorage.js';
const transactions = await loadTransactions('transactions.json'); // top-level await
console.log(`${transactions.length} transactions loaded`);In chapter 26, we'll add clean error handling to this system – failing await calls throw a regular JavaScript error, which we can catch with try/catch, instead of needing .catch() chains.