javascript - Promise.resolve vs new Promise(resolve)


Jag använder bluebird och jag ser två sätt att lösa synkrona funktioner till ett Promise, men jag förstår inte skillnaderna mellan de båda sätten. Det ser ut som att stacktracen är lite annorlunda, så de är inte bara ett alias, eller hur?

Så vad är det föredragna sättet?

Sätt A

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

Väg B

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

Svar #1

Tvärtemot båda svaren i kommentarerna - det finns en skillnad.

Medan

Promise.resolve(x);

är i princip samma som

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

det finns en subtilitet.

Funktioner som returnerar Promise bör generellt ha garantin att de inte kastar synkront eftersom de kan kasta asynkront. För att förhindra oväntade resultat och tävlingsförhållanden - kast omvandlas vanligtvis till returnerade avslag.

Med detta i åtanke - när specifikationen skapades är promise-konstruktören kastningssäker.

Vad händer om someObject är undefined?

  • Väg A returnerar ett avvisat löfte.
  • Sätt B kastar synkront.

Bluebird såg detta, och Petka lade till Promise.method för att åtgärda detta problem så att du kan fortsätta använda returvärden. Så det korrekta och enklaste sättet att skriva detta i Bluebird är faktiskt varken - det är:

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

Promise.method kommer att omvandla throws till rejects och returns till resolves åt dig. Det är det mest throw-säkra sättet att göra detta och det assimilerar thenables genom returvärden så det skulle fungera även om someObject faktiskt är ett promise i sig själv.

I allmänhet används Promise.resolve för att kasta objekt och externa löften (thenables) till löften. Det är dess användningsfall.

Svar #2

Det finns en annan skillnad som inte nämnts av de ovanstående svaren eller kommentarerna:

Om someObject är ett Promise, skulle new Promise(resolve) kosta två extra tick.

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(resolve => setTimeout(resolve));

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

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

Den andra kodbiten skulle skriva ut 'tick 3' först. Varför?

  • Om värdet är ett löfte, skulle Promise.resolve(value) returnera värdet exakt. Promise.resolve(value) === value skulle vara sant. se MDN

  • Men new Promise(resolve => resolve(value)) skulle returnera ett nytt löfte som har låst sig för att följa value-löftet. Det behöver en extra tick för att göra 'inlåsningen'.

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

    tick 1 .then-anropet skulle köras först.

  • http://exploringjs.com/es6/ch_promises.html#sec_demo-promise

Relaterade artiklar