JS engineres.statususer.namefetch()res.json()/api/usersGET /api/users/7 HTTP/1.1HTTP/1.1 200 OKContent-Type: application/json{"id":7,"name":"Ada"}1async function loadUser() {2 const res = await fetch("/api/users/7");3 if (!res.ok) throw new Error(res.status);4 const user = await res.json();5 console.log(user.name);6}7loadUser();8console.log("waiting...");Consolewaiting...user.js:8Adauser.js:5waiting...200AdaAda404Error: 404
Back: the browser (engine, promises, memory) and the server, joined by the networkFront: the HTTP messages, the script user.js and the developer consoleTokens: the request and response, the paused function and the values 200 and AdaAt the back, the browser's JavaScript engine with two promise boxes and two memory boxes, and the server joined to it by the network. In front, the HTTP messages, the script user.js and the console. fetch sends the request and hands back a pending promise at once; await parks loadUser on it while line 8 prints waiting.... The response fulfils the promise, loadUser carries on, checks res.ok, waits again for res.json() and prints Ada. A 404 reply still fulfils fetch's promise, so line 3 has to throw. fetch is not part of the JavaScript language itself: it is a web API defined by the WHATWG Fetch Standard and built into every modern browser. Node.js has it built in since version 18. Promises, async and await are part of the language (ECMA-262).

Asking a server

  1. A web page often needs data that lives on a server. fetch(url) is the browser's built-in way to ask: it sends an HTTP request (the web's message format) and returns a promise, a placeholder for an answer that arrives later.

Sending the request

The response comes back

When it goes wrong

What happens

// step 1/11 · fetch-idea
fetch(url)   send an HTTP request to url
returns      a promise, straight away
later        the promise fulfils with a Response
defined by   the WHATWG Fetch Standard
             (built into browsers and Node.js 18+)

fetch's promise fulfils as soon as the status and headers arrive; the body may still be downloading. That is why reading it with res.json() or res.text() returns another promise. A body can be read only once. fetch rejects (usually with a TypeError) only when no response comes back: no connection, a blocked cross-site request or a bad address. If you cancel a request with an AbortController, it rejects with an AbortError instead. To handle every failure, wrap the awaits in try { ... } catch (err) { ... }, or call loadUser().catch(...).