web-dev-qa-db-ja.com

Promise.resolveと新しいPromise(resolve)

私はbluebirdを使用していますが、同期関数をPromiseに解決する方法は2つありますが、両方の方法に違いはありません。スタックトレースは少し異なるように見えるので、それらはaliasだけではありませんよね?

それでは、好ましい方法は何ですか?

ウェイA

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

ウェイB

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

コメントの両方の答えに反して、違いがあります。

ながら

Promise.resolve(x);

基本的にと同じです

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

微妙なところがあります。

通常、Promiseを返す関数は、非同期でスローする可能性があるため、同期でスローしないことを保証する必要があります。予期しない結果と競合状態を防ぐために、スローは通常、返された拒否に変換されます。

これを念頭に置いて-仕様が作成されたとき、promiseコンストラクターは安全にスローされます。

someObjectundefinedである場合はどうなりますか?

  • ウェイAは拒否された約束を返します。
  • ウェイBは同期的にスローします。

Bluebirdはこれを見て、PetkaがPromise.methodを追加してこの問題に対処し、戻り値を使い続けることができるようにしました。したがって、これをBluebirdで記述する最も簡単で正しい方法は、実際はどちらでもありません。

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

Promise.methodは、スローを拒否に変換し、解決に戻ります。これは最も安全な方法であり、戻り値を通じてthenablesを同化するので、someObjectが実際に約束そのものであっても機能します。

一般に、Promise.resolveは、オブジェクトと外部プロミス(thenables)をプロミスにキャストするために使用されます。それがユースケースです。

70

上記の回答やコメントで言及されていない別の違いがあります。

someObjectが保留中のPromiseである場合、new Promise(resolve)は1ティック追加されます。


次の2つのコードスニペットを比較します。

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

2番目のスニペットは、最初に 'tick 3'を出力します。どうして?

  • 値がプロミスの場合、Promise.resolve(value)は正確に値を返します。 Promise.resolve(value) === valueはtrueになります。 [〜#〜] mdn [〜#〜] を参照してください

  • しかし、new Promise(resolve => resolve(value))は、value promiseに追従するためにロックされた新しいpromiseを返します。 「ロックイン」を行うには、追加の1ティックが必要です。

    _// 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_呼び出しが最初に実行されます。


参照:

8
edvard chen