Perché .json () restituisce una promise?

Recentemente ho lavorato con la fetch () api e ho notato qualcosa che era un po ‘bizzarro.

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 restituisce un object promise. http://jsbin.com/wofulo/2/edit?js,output

Tuttavia se è scritto come:

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

post qui è un object standard a cui è ansible accedere all’attributo title. http://jsbin.com/wofulo/edit?js,output

Quindi la mia domanda è: perché response.json restituisce una promise in un object letterale, ma restituisce il valore se appena restituito?

Perché response.json restituisce una promise?

Perché ricevi la response quando tutte le intestazioni sono arrivate. Chiamando .json() ottiene una promise per il corpo della risposta http che deve ancora essere caricata. Vedi anche Perché l’object risposta da API di recupero JavaScript è una promise? .

Perché ottengo il valore se restituisco la promise dal gestore then ?

Perché è così che funzionano le promesse . La possibilità di restituire le promesse dal callback e farle adottare è la loro caratteristica più rilevante, che le rende concatenabili senza nidificazione.

Puoi usare

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

o qualsiasi altro approccio per accedere ai risultati precedenti della promise in una catena .then () per ottenere lo stato della risposta dopo aver atteso il corpo JSON.

Questa differenza è dovuta al comportamento di Promises more than fetch() particolare.

Quando un callback .then() restituisce una Promise aggiuntiva, il prossimo callback .then() nella catena è essenzialmente legato a quella Promessa, ricevendo la sua risoluzione o rifiuto di adempimento e valore.

Il secondo snippet potrebbe anche essere stato scritto come:

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

In entrambi questo modulo e il tuo, il valore del post è fornito dalla Promessa restituita da response.json() .


Quando si restituisce un Object semplice, tuttavia, .then() considera che un risultato positivo e si risolve immediatamente, simile a:

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

post in questo caso è semplicemente l’ Object hai creato, che contiene una Promise nella sua proprietà data . L’attesa che la promise sia soddisfatta è ancora incompleta.

Oltre alle risposte di cui sopra, ecco come potresti gestire una risposta in serie 500 dalla tua api in cui ricevi un messaggio di errore codificato in 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 } 

Inoltre, ciò che mi ha aiutato a capire questo particolare scenario che hai descritto è la documentazione dell’API Promise, in particolare dove spiega come il promesso restituito dal metodo then verrà risolto in modo diverso a seconda di cosa restituisce il gestore fn :

se la funzione del gestore:

  • restituisce un valore, la promise restituita viene quindi risolta con il valore restituito come valore;
  • genera un errore, la promise restituita viene quindi respinta con l’errore generato come valore;
  • restituisce una promise già risolta, la promise restituita da allora viene risolta con il valore di quella promise come valore;
  • restituisce una promise già respinta, la promise restituita viene quindi respinta con il valore di quella promise come valore.
  • restituisce un altro object promise in sospeso, la risoluzione / rifiuto della promise restituita da allora sarà successiva alla risoluzione / rifiuto della promise restituita dal gestore. Inoltre, il valore della promise restituita da allora sarà uguale al valore della promise restituita dal gestore.