Promise.resolve vs nuova promessa (risoluzione)


94

Sto usando bluebird e vedo due modi per risolvere le funzioni sincrone in una promessa, ma non ottengo le differenze tra i due modi. Sembra che lo stacktrace sia leggermente diverso, quindi non sono solo un alias, giusto?

Allora qual è il modo preferito?

Modo A

function someFunction(someObject) {
  return new Promise(function(resolve) {
    someObject.resolved = true;
    resolve(someObject);
  });
}

Modo B

function someFunction(someObject) {
  someObject.resolved = true;
  return Promise.resolve(someObject);
}

3
Promise.resolveè solo zucchero.
Qantas 94 Heavy

1
Risposta breve: nessuna differenza nell'utilizzo. Solo zucchero.
Pinal

@Pinal Cos'è lo "zucchero"?
doubleOrt

5
@Toro. Lo zucchero sintattico è una sintassi progettata per rendere le cose più facili da leggere o esprimere. vedi: wikipedia .
Wyck

Risposte:


82

Contrariamente a entrambe le risposte nei commenti, c'è una differenza.

Mentre

Promise.resolve(x);

è fondamentalmente lo stesso di

new Promise(function(r){ r(x); });

c'è una sottigliezza.

Le funzioni di restituzione della promessa dovrebbero generalmente avere la garanzia che non dovrebbero essere lanciate in modo sincrono poiché potrebbero essere lanciate in modo asincrono. Per evitare risultati imprevisti e condizioni di gara, i lanci vengono solitamente convertiti in rifiuti restituiti.

Con questo in mente, quando la specifica è stata creata, il costruttore della promessa è sicuro.

E se lo someObjectfosse undefined?

  • Way A restituisce una promessa rifiutata.
  • Il modo B lancia in modo sincrono.

Bluebird lo ha visto e Petka ha aggiunto Promise.methodper risolvere questo problema in modo da poter continuare a utilizzare i valori di ritorno. Quindi il modo corretto e più semplice per scrivere questo in Bluebird non è in realtà né l'uno né l'altro: è:

var someFunction = Promise.method(function someFunction(someObject){
    someObject.resolved = true;
    return someObject;
});

Promise.method convertirà i lanci in rifiuti e restituirà le risoluzioni per te. È il modo più sicuro per farlo e assimila le capacità thenattraverso i valori di ritorno, quindi funzionerebbe anche se someObjectin realtà è una promessa stessa.

In generale, Promise.resolveviene utilizzato per la fusione di oggetti e promesse estere (thenables) in promesse. Questo è il suo caso d'uso.


"Le funzioni di restituzione della promessa dovrebbero generalmente avere la garanzia che non dovrebbero essere lanciate in modo sincrono poiché potrebbero essere lanciate in modo asincrono". Potresti approfondire il motivo per cui le funzioni dovrebbero essere sincrone o asincrone ma non entrambe? Attualmente mi piace Promise.resolve (), ti spingeresti a dire che l'uso Promise.resolve()è un anti-pattern?
Ashley Coolman

2
@AshleyCoolman vedi blog.izs.me/post/59142742143/designing-apis-for-asynchrony - un metodo che a volte si comporta in modo asincrono dovrebbe sempre farlo per coerenza.
Benjamin Gruenbaum

Non Promise.resolve()creare una nuova istanza Promisenello stesso modo come l'utilizzo new? In caso contrario, return Promise.resolve(yourCode)sarebbe più veloce ed eviterebbe lanci sincroni.
Steven Vachon

1
Mi dispiace, utilizzo "Promise.resolve (). Then (function () {/ * case that can throw an error * /}). Then ..." per essere sicuro che l'errore diventi una promessa rifiutata ... Approfondirò il "Promise.method"
Polopollo

1
@Polopollo o Promise.coroutineche è ancora più utile.
Benjamin Gruenbaum

16

C'è un'altra differenza non menzionata nelle risposte o nei commenti sopra:

Se someObjectè a Promise, new Promise(resolve)costerebbe due tick aggiuntivi.


Confronta due seguenti snippet di codice:

const p = new Promise(resovle => setTimeout(resovle));

new Promise(resolve => resolve(p)).then(() => {
  console.log("tick 3");
});

p.then(() => {
  console.log("tick 1");
}).then(() => {
  console.log("tick 2");
});

const p = new Promise(resovle => setTimeout(resovle));

Promise.resolve(p).then(() => {
  console.log("tick 3");
});

p.then(() => {
  console.log("tick 1");
}).then(() => {
  console.log("tick 2");
});

Il secondo frammento stampa prima "segno di spunta 3". Perché?

  • Se il valore è una promessa, Promise.resolve(value)restituirà esattamente valore. Promise.resolve(value) === valuesarebbe vero. vedi MDN

  • Ma new Promise(resolve => resolve(value))restituirebbe una nuova promessa che si è bloccata per seguire la valuepromessa. È necessario un segno di spunta in più per effettuare il "blocco".

    // something like:
    addToMicroTaskQueue(() => {
      p.then(() => {
        /* resolve newly promise */
      })
        // all subsequent .then on newly promise go on from here
        .then(() => {
          console.log("tick 3");
        });
    });

    La tick 1 .thenchiamata verrebbe eseguita per prima.


Riferimenti:

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.