Pourquoi .json () renvoie-t-il une promesse?

Je me suis amusé avec l’api fetch () récemment et j’ai remarqué quelque chose qui était un peu bizarre.

let url = "http://jsonplaceholder.typicode.com/posts/6"; let iterator = fetch(url); iterator .then(response => { return { data: response.json(), status: response.status } }) .then(post => document.write(post.data)); ; 

post.data renvoie un object promis. http://jsbin.com/wofulo/2/edit?js,output

Cependant s’il est écrit comme:

 let url = "http://jsonplaceholder.typicode.com/posts/6"; let iterator = fetch(url); iterator .then(response => response.json()) .then(post => document.write(post.title)); ; 

post here est un object standard auquel vous pouvez accéder avec l’atsortingbut title. http://jsbin.com/wofulo/edit?js,output

Donc, ma question est la suivante: pourquoi response.json renvoie-t-il une promesse dans un littéral d’object, mais renvoie la valeur si elle est simplement retournée?

Pourquoi response.json renvoie-t-il une promesse?

Parce que vous recevez la response lorsque tous les en-têtes sont arrivés. L’appel de .json() vous donne une promesse pour le corps de la réponse http à charger. Voir aussi Pourquoi l’object de réponse de JavaScript récupère-t-il une promesse? .

Pourquoi est-ce que j’obtiens la valeur si je retourne la promesse du gestionnaire then ?

Parce que c’est comme ça que les promesses fonctionnent . La possibilité de renvoyer des promesses à partir du rappel et de les faire adopter est leur caractéristique la plus pertinente, elles les rendent chaînables sans imbrication.

Vous pouvez utiliser

 fetch(url).then(response => response.json().then(data => ({ data: data, status: response.status }) ).then(res => { console.log(res.status, res.data.title) })); 

ou toute autre approche pour accéder à la promesse précédente aboutit à une chaîne .then () pour obtenir le statut de la réponse après avoir attendu le corps json.

Cette différence est due au comportement de Promises plus que fetch() spécifiquement.

Lorsqu’un rappel .then() renvoie une Promise supplémentaire, le prochain rappel .then() de la chaîne est essentiellement lié à cette promesse, recevant sa résolution ou son rejet et sa valeur.

Le 2ème extrait pourrait aussi avoir été écrit comme suit:

 iterator.then(response => response.json().then(post => document.write(post.title)) ); 

Dans ce formulaire et dans le vôtre, la valeur de post est fournie par la promesse renvoyée par response.json() .


Lorsque vous retournez un Object brut, cependant, .then() considère que le résultat est .then() et se résout immédiatement, comme dans:

 iterator.then(response => Promise.resolve({ data: response.json(), status: response.status }) .then(post => document.write(post.data)) ); 

post dans ce cas est simplement l’ Object vous avez créé, qui contient une Promise dans sa propriété data . L’attente de la réalisation de cette promesse est encore incomplète.

En plus des réponses ci-dessus, voici comment vous pouvez gérer une réponse de la série 500 à partir de votre API où vous recevez un message d’erreur codé dans json:

 function callApi(url) { return fetch(url) .then(response => { if (response.ok) { return response.json().then(response => ({ response })); } return response.json().then(error => ({ error })); }) ; } let url = 'http://jsonplaceholder.typicode.com/posts/6'; const { response, error } = callApi(url); if (response) { // handle json decoded response } else { // handle json decoded 500 series response } 

En outre, ce qui m’a aidé à comprendre ce scénario particulier que vous avez décrit est la documentation de l’ API Promise, en particulier là où elle explique comment la promesse retournée par la méthode then sera résolue différemment selon ce que fn renvoie le gestionnaire :

si le gestionnaire fonctionne:

  • renvoie une valeur, la promesse renvoyée est alors résolue avec la valeur renvoyée comme valeur;
  • jette une erreur, la promesse renvoyée est rejetée avec l’erreur renvoyée comme valeur;
  • renvoie une promesse déjà résolue, la promesse renvoyée se résout alors avec la valeur de cette promesse;
  • renvoie une promesse déjà rejetée, la promesse renvoyée est alors rejetée avec la valeur de cette promesse.
  • renvoie un autre object promis en attente, la résolution / rejet de la promesse renvoyée par la suite sera postérieure à la résolution / rejet de la promesse renvoyée par le gestionnaire. De plus, la valeur de la promesse renvoyée par la suite sera la même que celle de la promesse renvoyée par le gestionnaire.