Je me suis amusé avec la fetch()
api récemment, et j'ai remarqué quelque chose d'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 objet Promise
. http://jsbin.com/wofulo/2/edit?js,output
Cependant, si c'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
voici un Object
standard auquel vous pouvez accéder à l'attribut title. http://jsbin.com/wofulo/edit?js,output
Ma question est donc la suivante: pourquoi response.json
renvoie-t-il une promesse dans un objet littéral, mais renvoie-t-il la valeur s'il vient d'être renvoyé?
Pourquoi
response.json
renvoie-t-il une promesse?
Parce que vous recevez la response
dès que tous les en-têtes sont arrivés. L'appel de .json()
vous procure une autre promesse pour le corps de la réponse http qui n'a pas encore été chargé. Voir aussi Pourquoi l'objet de réponse de l'API de récupération de JavaScript est-il une promesse? .
Pourquoi ai-je la valeur si je retourne la promesse du gestionnaire
then
?
Parce que c'est comme ça que les promesses marchent . La possibilité de retourner des promesses à partir du rappel et de les faire adopter est leur caractéristique la plus pertinente, cela les rend 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 des les approches permettant d'accéder aux promesses précédentes aboutissent à une chaîne .then () pour obtenir l'état 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 un Promise
supplémentaire, le prochain rappel .then()
de la chaîne est essentiellement lié à cette promesse, recevant sa résolution ou rejetant l'exécution et la valeur.
Le deuxième extrait aurait également pu être écrit comme suit:
iterator.then(response =>
response.json().then(post => document.write(post.title))
);
Dans ce formulaire et le vôtre, la valeur de post
est fournie par la promesse renvoyée par response.json()
.
Lorsque vous renvoyez un Object
brut, cependant, .then()
considère qu'un résultat est réussi et se résout immédiatement, comme suit:
iterator.then(response =>
Promise.resolve({
data: response.json(),
status: response.status
})
.then(post => document.write(post.data))
);
post
est dans ce cas simplement la Object
que vous avez créée et qui contient une Promise
dans sa propriété data
. L'attente pour que cette promesse soit remplie est encore incomplète.
En outre, ce qui m'a aidé à comprendre ce scénario particulier que vous avez décrit est l'API Promise documentation , où il explique en particulier comment la promesse renvoyée par la méthode then
sera résolue différemment en fonction de ce que gestionnaire fn renvoie:
si la fonction de gestionnaire:
- renvoie une valeur, la promesse renvoyée à ce moment-là est résolue avec la valeur renvoyée comme valeur;
- renvoie une erreur, la promesse renvoyée à l’époque est rejetée avec l’erreur renvoyée comme valeur;
- retourne une promesse déjà résolue, la promesse retournée d'ici est résolue avec la valeur de cette promesse comme valeur;
- renvoie une promesse déjà rejetée, la promesse retournée à cette date est rejetée avec la valeur de cette promesse comme valeur.
- renvoie un autre objet de promesse en attente, la résolution/le rejet de la promesse retournée à ce moment-là sera postérieur à la résolution/le rejet de la promesse renvoyée par le gestionnaire. En outre, la valeur de la promesse renvoyée à ce moment-là sera la même que la valeur de la promesse renvoyée par le gestionnaire.
En plus des réponses ci-dessus, voici comment vous pouvez gérer une réponse de la série 500 de votre API lorsque vous recevez un message d'erreur codé en 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
}