Promise.resolve vs new Promise (resolver)

94

Estou usando o bluebird e vejo duas maneiras de resolver funções síncronas em uma promessa, mas não entendo as diferenças entre as duas maneiras. Parece que o stacktrace é um pouco diferente, então eles não são apenas um alias, certo?

Então, qual é a forma preferida?

Caminho A

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

Caminho B

function someFunction(someObject) {
  someObject.resolved = true;
  return Promise.resolve(someObject);
}
Pipo
fonte
3
Promise.resolveé apenas açúcar.
Qantas 94 Heavy
1
Resposta curta - sem diferença no uso. Só açúcar.
Pinal
@Pinal O que é "açúcar"?
doubleOrt
5
@Touro. Açúcar sintático é uma sintaxe projetada para tornar as coisas mais fáceis de ler ou expressar. veja: wikipedia .
Wyck

Respostas:

82

Ao contrário de ambas as respostas nos comentários - há uma diferença.

Enquanto

Promise.resolve(x);

é basicamente o mesmo que

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

existe uma sutileza.

As funções de retorno de promessa geralmente devem ter a garantia de que não devem ser lançadas de forma síncrona, pois podem ser lançadas de forma assíncrona. Para evitar resultados inesperados e condições de corrida - os lançamentos são geralmente convertidos em rejeições devolvidas.

Com isso em mente - quando a especificação foi criada, o construtor de promessa está seguro.

E se someObjectfor undefined?

  • O Caminho A retorna uma promessa rejeitada.
  • Way B joga sincronizadamente.

Bluebird viu isso e Petka acrescentou Promise.methodpara resolver esse problema para que você possa continuar usando valores de retorno. Portanto, a maneira correta e mais fácil de escrever isso no Bluebird é, na verdade, nenhuma das duas - é:

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

Promise.method irá converter lances em rejeições e retornos em resoluções para você. É a maneira mais segura de fazer isso e assimila thenhabilidades por meio de valores de retorno para que funcione mesmo que someObjectseja de fato uma promessa em si.

Em geral, Promise.resolveé usado para lançar objetos e promessas estrangeiras (thenables) para promessas. Esse é o seu caso de uso.

Benjamin Gruenbaum
fonte
"Funções de retorno de promessa geralmente devem ter a garantia de que não devem ser lançadas de forma síncrona, pois podem ser lançadas de forma assíncrona". Você poderia explicar por que as funções devem ser síncronas ou assíncronas, mas não ambas? Atualmente eu gosto de Promise.resolve (), você diria que usar Promise.resolve()é um antipadrão ?
Ashley Coolman
2
@AshleyCoolman consulte blog.izs.me/post/59142742143/designing-apis-for-asynchrony - um método que às vezes se comporta de forma assíncrona deve sempre fazê-lo para consistência.
Benjamin Gruenbaum
Cria Promise.resolve()uma nova instância de Promiseda mesma maneira que usa new? Caso contrário, return Promise.resolve(yourCode)seria mais rápido e evitaria lançamentos síncronos.
Steven Vachon
1
Me sinto mal, uso "Promise.resolve (). Then (function () {/ * case que pode gerar um erro * /}). Then ..." para ter certeza de que o erro se torna uma promessa rejeitada ... Vou dar uma olhada mais em "Promise.method"
Polopollo
1
@Polopollo ou o Promise.coroutineque é ainda mais útil.
Benjamin Gruenbaum
16

Há outra diferença não mencionada pelas respostas ou comentários acima:

Se someObjectfor um Promise, new Promise(resolve)custaria dois carrapatos adicionais.


Compare os dois seguintes snippet de código:

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");
});

O segundo trecho imprimiria 'tick 3' primeiro. Por quê?

  • Se o valor for uma promessa, Promise.resolve(value)retornaria o valor exatamente. Promise.resolve(value) === valueseria verdade. veja MDN

  • Mas new Promise(resolve => resolve(value))retornaria uma nova promessa que travou para seguir a valuepromessa. É necessária uma marcação extra para fazer o 'bloqueio'.

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

    A tick 1 .thenchamada seria executada primeiro.


Referências:

edvard chen
fonte