2016-05-31 7 views
28

Ich habe vor kurzem mit der fetch() api herumgespielt, und bemerkte etwas, das ein bisschen skurril war.Warum gibt .json() ein Versprechen zurück, wenn es sich in einem Objektliteral befindet?

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 gibt ein Zusicherungsobjekt zurück. http://jsbin.com/wofulo/2/edit?js,output

Allerdings, wenn es geschrieben wird als:

let url = "http://jsonplaceholder.typicode.com/posts/6"; 

let iterator = fetch(url); 

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

Beitrag hier ein Standard-Objekt, mit dem Sie den Titel-Attribut zugreifen können. http://jsbin.com/wofulo/edit?js,output

Also meine Frage ist: Warum tut response.json ein Versprechen in einem Objektliteral zurück, aber den Wert zurück, wenn gerade zurückgekehrt?

+0

Dies ist sinnvoll, wenn Sie in Betracht ziehen, dass die Antwort "response.json()" möglicherweise abgelehnt wird, wenn die Antwort nicht gültig ist JSON. – ssube

+0

Der Wert wird zurückgegeben, weil das Versprechen gelöst wurde und der Wert in response.json() übergeben wurde. Jetzt ist der Wert in der then-Methode verfügbar. –

Antwort

40

Warum gibt response.json ein Versprechen zurück?

Weil Sie die response erhalten, wenn alle Überschriften angekommen sind. Wenn Sie .json() aufrufen, erhalten Sie ein Versprechen für den Hauptteil der http-Antwort, die noch geladen werden soll. Siehe auch Why the response object from JavaScript fetch API is a promise?.

Warum bekomme ich den Wert, wenn ich das Versprechen vom then Handler zurückgebe?

Weil that's how promises work. Die Fähigkeit, Versprechen aus dem Callback zurückzugeben und sie adoptieren zu lassen, ist ihre wichtigste Eigenschaft, sie macht sie verkettbar, ohne zu verschachteln.

können Sie

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

oder anderen der approaches to access previous promise results in a .then() chain verwenden, um den Antwortstatus zu erhalten, nachdem die json Körper erwartet hat.

+0

Es scheint komisch, dass ich nicht einfach warten kann, bis die Daten mit einem Versprechen zurückkommen, und wenn es angekommen ist, wandle es in json um? Oder vielleicht könnte ich in diesem Fall 'JSON.parse()' anstelle von 'res.json()' ?? – Kokodoko

+1

@Kokodoko 'res.json()' ist im Grunde eine Abkürzung für 'res.text(). Then (JSON.parse)'. Beide warten mit einem Versprechen auf die Daten und analysieren den JSON. – Bergi

9

Dieser Unterschied ist aufgrund des Verhaltens von Promises mehr als fetch() spezifisch.

Wenn ein Rückruf .then() ein zusätzliches Promise zurückgibt, wird der nächste .then() Rückruf in der Kette im Wesentlichen auf dieses Versprechen, empfängt seinen Willen oder ablehnen Erfüllung und Wert gebunden.

Der zweite Schnipsel auch geschrieben haben könnte als:

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

In beiden dieser Form und Ihnen, wird der Wert von post bereitgestellt durch das Versprechen von response.json() zurückgegeben.


Wenn Sie eine einfache Object zurückkehren, obwohl hält .then(), dass ein erfolgreiches Ergebnis und löst sich sofort ähnlich:

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

post ist in diesem Fall einfach die Object Sie erstellt, die hält a Promise in seiner data Eigenschaft. Das Warten auf dieses Versprechen ist noch nicht abgeschlossen.

2

Zusätzlich zu den oben genannten Antworten sind hier, wie Sie vielleicht eine 500-Serie Antwort von Ihrem api behandeln, in denen Sie eine Fehlermeldung in json codiert erhalten:

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 
} 
0

Auch, was mir geholfen, dieses bestimmte Szenario zu verstehen, dass Sie beschrieben ist das Versprechen API documentation, wo es ausdrücklich erklärt, wie die von der then-Methode zurück versprochene wird anders gelöst werden, je nachdem, was der Handler fn kehrt:

Wenn die Handler-Funktion:

  • einen Wert zurückgibt, wird die bis dahin zurückgegebene Antwort mit dem zurückgegebenen Wert als Wert aufgelöst.
  • löst einen Fehler aus, die bis dahin zurückgegebene Zusage wird mit dem geworfenen Fehler als Wert abgelehnt;
  • gibt ein bereits aufgelöstes Versprechen zurück, das bis dahin zurückgegebene Versprechen wird mit dem Wert dieses Versprechens als Wert aufgelöst;
  • gibt eine bereits abgelehnte Zusage zurück, die bis dahin zurückgegebene Zusage wird mit dem Wert dieser Zusage als Wert abgelehnt.
  • gibt ein weiteres ausstehendes Zusicherungsobjekt zurück, die Auflösung/Zurückweisung der bis dahin zurückgegebenen Zusage erfolgt nach der Auflösung/Ablehnung der vom Behandler zurückgegebenen Zusage. Außerdem ist der Wert der bis dahin zurückgegebenen Zusage derselbe wie der Wert die vom Handler zurückgegebene Zusage.