To API fetch
returns a Promise
with a Response
, which contains various data relating to the response to the request, such as status, URL or the body itself (body
).
However, the property body
of Response
is a ReadableStream
, which would make its direct use relatively costly for an easy to use API. Thus, for convenience, Response
also has some methods such as the json
, text
and others, that help in the conversion of the body, a ReadableStream
, for more easily usable formats.
For this, these methods (such as json
or text
) should also return another Promise
, since usually work with Streams is asynchronous.
Therefore, as we are working with two promises (one returned by fetch
and another returned by the method json
of Response
), you have to chain them up using the then
:
fetch('<url>') /* `fetch` retorna uma promessa. */
.then /* Liga-se à resolução da promessa do `fetch`. */ ((response) => response.json() /* `json` retorna OUTRA promessa. */ )
.then /* Liga-se à resolução da promessa método `json` de `Response`. */ ((data) => console.log(data))
.catch(console.error);
To demonstrate that we work with two promises, if we use async
/await
, we would have to use the operator await
twice, once to settle the promise of fetch
and the other to settle the promise of json
:
async function main() {
// Espera a resolução da promessa do `fetch`.
// ↓↓↓↓↓
const response = await fetch('<url>');
// Espera a resolução da promessa do `json`.
// ↓↓↓↓↓
const data = await response.json();
console.log(data);
}
main().catch(console.error);
Thus, clarifying some parts of the question:
In the first then
should no longer receive a complete response from the server?
Yes, and that’s exactly what’s happening. The fetch
returns a Promise
with Response
, an object that contains several properties of the response - including its body. Despite this, the body is not yet in the format we want, which makes it necessary to use methods such as the json
: to convert body
, a Stream, in a JSON.
If in the first then
I don’t have that information, why would I have on the second if he’s a callback of the first?
The second then
is by no means a callback of the first. The second then
is a tool to wait for method resolution json
present in Response
. Are two different things.
Behold:
fetch('https://api.github.com/users')
.then((response) => {
console.log('Propriedades e métodos de `response`:');
console.log(Object.keys(response.__proto__));
// Note que deste `then` estamos retornando uma outra promessa.
// Isso porque este método `json` retorna uma OUTRA `Promise`.
return response.json();
})
.then((data) => {
console.log('Agora sim temos o nosso JSON "parseado":');
console.log(data.length); // Número de dados retornados pela API. Não interessa para a explicação.
});
It is worth saying that as soon as the first then
is executed, that is, the promise of fetch
is resolved, the request has already been completed and its body is in the browser’s memory. From there, all that remains is to transform Stream into JSON. :)
I repeated several times some things in this answer, I hope you didn’t get bored.