Tom on the Internet

Why Two Awaits?

You've seen these two await calls before.

let response = await fetch("/some-url")
let myObject = await response.json()

Awaiting fetch makes sense because we don't want to block the main thread while we make a network request.

But, why do we need to await response.json()?

Parsing JSON shouldn't take a long time. In fact, we regularly call JSON.parse() which is a synchronous call. So, why does response.json() return a promise?

What's going on?

From MDN's article on the Fetch API:

The fetch() method takes one mandatory argument, the path to the resource you want to fetch. It returns a Promise that resolves to the Response to that request — as soon as the server responds with headers — even if the server response is an HTTP error status.

So, fetch resolves the response before the body has necessarily been completely received.

Looking at the code from earlier:

let response = await fetch("/some-url")
// 1. the client has received the headers
// 2. the body is (probably) still making its way over.

let myObject = await response.json()
// 3. the client has received the body
// 4. the client has tried to parse the body as JSON

It's useful it is to have access to the headers before the whole body arrives. Based on the status code, or one of the headers, we might decide to not read the body at all.

And the body arriving after the headers is actually something we're used to. This is how everything works in the browser. HTML is slowly sent over the wire, as are images, fonts, etc. I guess I was just confused by the name of the method: response.json().