Qual è la differenza tra il valore di ritorno o Promise.resolve da then ()


314

Qual è la differenza tra:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return "bbb";
  })
  .then(function(result) {
    console.log(result);
  });

e questo:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return Promise.resolve("bbb");
  })
  .then(function(result) {
    console.log(result);
  });

Sto chiedendo come sto ottenendo un comportamento diverso Usando il servizio Angular e $ http con il concatenamento .then (). Un po 'troppo di codice, quindi prima l'esempio sopra.


1
Quale "comportamento diverso" stai vedendo? Entrambi gli esempi dovrebbero funzionare e comportarsi all'incirca allo stesso modo. Il Promise.resolve()secondo esempio non è necessario.
JLRishe,

4
@pixelbits Non c'è nulla di sbagliato nel restituire una promessa da un thengestore, in effetti è un aspetto chiave delle specifiche delle promesse che puoi farlo.

Si noti che questo funziona con thens nidificati in modo arbitrario - il termine "altre lingue" per questo è che thensia a mapche a flatMap.
Benjamin Gruenbaum,

1
nella riga 2 perché è necessario chiamare res ("aaa"), perché non è possibile restituire "aaa" essere sufficiente e Promise cattura per risolverlo () nello stesso modo in cui rileva le eccezioni per rifiutare ()?
Sam Liddicott,

1
@SamLiddicott ha la stessa domanda, mentre le mine sono un po 'più complicate: new Promise((res, rej) => { return fetch('//google.com').then(() => { return "haha"; }) }).then((result) => alert(result));questo codice si bloccherà (non risolto per sempre). Ma se cambio return "haha";a return res("haha");allora funzionerà e avviserà "haha". Fetch (). Then () non ha già avvolto "haha" in una promessa risolta?
Shaung Cheng,

Risposte:


138

La regola è, se la funzione che si trova nel thengestore restituisce un valore, la promessa si risolve / rifiuta con quel valore e se la funzione restituisce una promessa, ciò che accade è, la thenclausola successiva sarà la thenclausola della promessa restituita dalla funzione , quindi, in questo caso, il primo esempio cade attraverso la normale sequenza di thense stampa i valori come ci si potrebbe aspettare, nel secondo esempio, l'oggetto promessa che viene restituito quando lo si fa Promise.resolve("bbb")è quello thenche viene invocato durante il concatenamento (a tutti gli effetti). Il modo in cui funziona effettivamente è descritto di seguito in modo più dettagliato.

Citando dalle promesse / A + specifiche:

La procedura di risoluzione delle promesse è un'operazione astratta che prende come input una promessa e un valore, che denotiamo come [[Resolve]](promise, x). Se xè possibile, cerca di far sì che la promessa adotti lo stato dix , supponendo che x si comporti almeno in qualche modo come una promessa . Altrimenti, mantiene la promessa con il valore x.

Questo trattamento dei prodotti in questione consente alle implementazioni promettenti di interagire, purché espongano un metodo conforme a Promises / A +. Inoltre, consente alle implementazioni Promises / A + di "assimilare" le implementazioni non conformi con metodi ragionevoli.

La cosa fondamentale da notare qui è questa riga:

se xè una promessa, adotta il suo stato [3.4]

link: https://promisesaplus.com/#point-49


4
"Adotta il suo stato" è un modo conciso e utile per esprimere il comportamento quando un thengestore restituisce una promessa. +1 per il riferimento alle specifiche.

69
In realtà - la parte rilevante della specifica qui è il fatto che [[Resolve]]viene chiamato sia su thenabilità che su valori, quindi essenzialmente avvolge un valore con la promessa, quindi return "aaa"è lo stesso di return Promise.resolve("aaa")ed return Promise.resolve("aaa")è lo stesso di return Promise.resolve(Promise.resolve("aaa"))- poiché la risoluzione è idempotente chiamandola su un valore più di una volta ha lo stesso risultato.
Benjamin Gruenbaum,

8
@Benjamin Gruenbaum significa che ritorno "aaa"e return Promise.resolve("aaa")sono intercambiabili in thenabilità in ogni caso?
CSnerd,

9
Sì, è esattamente ciò che significa.
Benjamin Gruenbaum,

118

In termini semplici, all'interno di a then funzione del gestore:

A) Quando xè un valore (numero, stringa, ecc.):

  1. return x è equivalente a return Promise.resolve(x)
  2. throw x è equivalente a return Promise.reject(x)

B) Quando xè una promessa già stabilita (non più in sospeso):

  1. return xè equivalente a return Promise.resolve(x), se la Promessa era già stata risolta.
  2. return xè equivalente a return Promise.reject(x), se la Promessa è stata già respinta.

C) Quando xè una promessa in sospeso:

  1. return xrestituirà una Promessa in sospeso e verrà valutata sulla successiva then.

Maggiori informazioni su questo argomento nei documenti Promise.prototype.then () .


93

Entrambi i tuoi esempi dovrebbero comportarsi più o meno allo stesso modo.

Un valore restituito all'interno di un then()gestore diventa il valore di risoluzione della promessa restituita da quello then(). Se il valore restituito all'interno di .then è una promessa, la promessa restituita dathen() "adotterà lo stato" di quella promessa e si risolverà / rifiuterà proprio come fa la promessa restituita.

Nel tuo primo esempio, ritorni "bbb"nel primo then()gestore, quindi "bbb"viene passato al then()gestore successivo .

Nel tuo secondo esempio, restituisci una promessa che viene immediatamente risolta con il valore "bbb", quindi "bbb"viene passata al then()gestore successivo . (Il Promise.resolve()qui è estraneo).

Il risultato è lo stesso.

Se puoi mostrarci un esempio che mostra effettivamente comportamenti diversi, possiamo dirti perché sta accadendo.


1
Bella risposta! Che dire di Promise.resolve();vs return;?
FabianTe

2
@FabianTe Anche quelli avrebbero lo stesso effetto, tranne con undefinedinvece di "bbb".
JLRishe,

51

Hai già una buona risposta formale. Ho pensato di aggiungerne uno breve.

Le seguenti cose sono identiche alle promesse / A + promesse:

  • Chiamata Promise.resolve(nel tuo caso angolare $q.when)
  • Chiamare il costruttore della promessa e risolverlo nel suo risolutore. Nel tuo caso è quello new $q.
  • Restituzione di un valore da a then richiamata.
  • Chiamata Promise.all su un array con un valore e quindi estrarre quel valore.

Quindi i seguenti sono tutti identici per una promessa o un semplice valore X:

Promise.resolve(x);
new Promise(function(resolve, reject){ resolve(x); });
Promise.resolve().then(function(){ return x; });
Promise.all([x]).then(function(arr){ return arr[0]; });

E non è una sorpresa, le specifiche delle promesse si basano sulla procedura di risoluzione delle promesse che consente una facile interazione tra le librerie (come $ q e promesse native) e semplifica la vita. Ogni volta che potrebbe verificarsi una risoluzione promettente, si verifica una risoluzione che crea coerenza generale.


posso chiederti qual è il punto nel fare Promise.resolve().then(function(){ return x; });? Ho trovato uno snipped che fa qualcosa di simile (ha chiamato una funzione all'interno del thenblocco). Ho pensato che fosse più o meno come fare un timeout, ma è un po 'più veloce. jsben.ch/HIfDo
Sampgun

Non ha senso è lo stesso di Promise.resolve (x) nel 99,99% dei casi. (lo 0,001% è che ci troviamo in un withblocco sopra un oggetto o un proxy con un xaccessor di proprietà che genera un'eccezione. In tal caso Promise.resolve (x) provocherebbe un errore generato ma Promise.resolve().then(function(){ return x; });sarebbe una promessa respinta poiché l'errore viene generato in a then).
Benjamin Gruenbaum,

hai collegato un blitz vuoto o non hai salvato. Comunque non stavo parlando delle differenze tra le dichiarazioni. Stavo parlando proprio di ciò che ho scritto. Giusto per essere più chiari, questo è il frammento di cui stavo parlando: if (validator) { Promise.resolve().then(() => { this._cdRef.markForCheck(); }); }. Qui la promessa non viene assegnata, quindi qual è il punto? Un timeout avrebbe (più o meno) lo stesso effetto o no?
Sampgun,

1
Esegue la chiamata in modo asincrono dopo che è stato eseguito tutto il codice sincrono ma prima che si verifichi qualsiasi I / O. Si chiama "semantica dei microtick".
Benjamin Gruenbaum,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.