89

ES6 promise を使用して、それを解決するためのロジックを定義せずに promise を作成するにはどうすればよいですか? 基本的な例を次に示します (一部の TypeScript)。

var promises = {};
function waitFor(key: string): Promise<any> {
  if (key in promises) {
    return promises[key];
  }
  var promise = new Promise(resolve => {
    // But I don't want to try resolving anything here :(
  });

  promises[key] = promise;
  return promise;
}

function resolveWith(key: string, value: any): void {
  promises[key].resolve(value); // Not valid :(
}

他の promise ライブラリで簡単に実行できます。JQuery の例:

var deferreds = {};
function waitFor(key: string): Promise<any> {
  if (key in promises) {
    return deferreds[key].promise();
  }
  var def = $.Deferred();    
  deferreds[key] = def;
  return def.promise();
}

function resolveWith(key: string, value: any): void {
  deferreds[key].resolve(value);
}

これを行う唯一の方法は、resolve 関数を promise のエグゼキューター内のどこかに保存することですが、それは面倒に思えます。この関数が正確に実行されたときに定義されているかどうかはわかりません-常に構築時にすぐに実行されますか?

ありがとう。

4

6 に答える 6

106

良い質問!

promise コンストラクターに渡されるリゾルバーは、このユース ケースをサポートするために意図的に同期的に実行されます。

var deferreds = [];
var p = new Promise(function(resolve, reject){
    deferreds.push({resolve: resolve, reject: reject});
});

その後、ある時点で次のようになります。

 deferreds[0].resolve("Hello"); // resolve the promise with "Hello"

promise コンストラクターが指定されている理由は次のとおりです。

  • 通常 (ただし常にではありません)、解決ロジックは作成にバインドされます。
  • promise コンストラクターは安全にスローされ、例外を拒否に変換します。

適合しない場合があり、そのためにリゾルバーは同期的に実行されます。このトピックに関する関連資料を次に示します

于 2015-06-26T09:23:12.080 に答える
59

ここに 2 セントを追加します。「解決を開始せずにes6 Promiseを作成する」という質問を正確に考慮して、ラッパー関数を作成し、代わりにラッパー関数を呼び出すことで解決しました。コード:

fPromise を返す関数があるとしましょう

/** @return Promise<any> */
function f(args) {
   return new Promise(....)
}

// calling f()
f('hello', 42).then((response) => { ... })

ここで、実際に解決せずに呼び出しを準備したいと思います。f('hello', 42)

const task = () => f('hello', 42) // not calling it actually

// later
task().then((response) => { ... })

これが誰かを助けることを願っています:)


&への呼び出しを準備Promise.all()したい場合は、コメントで尋ねられた (そして @Joe Frambach によって回答された) 参照、プロミスを返す 2 つの関数f1('super')f2('rainbow')

const f1 = args => new Promise( ... )
const f2 = args => new Promise( ... )

const tasks = [
  () => f1('super'),
  () => f2('rainbow')
]

// later
Promise.all(tasks.map(t => t()))
  .then(resolvedValues => { ... })
于 2016-11-24T13:22:03.390 に答える
3

より包括的なアプローチはどうですか?

.resolve()and.reject()メソッドで装飾された新しい Promise を返すコンストラクタを作成できます。

おそらく、コンストラクターに名前を付けるのを選択するでしょう。これDeferredは、JavaScript のプロミス [の歴史] で多くの優先順位を持つ用語です。

function Deferred(fn) {
    fn = fn || function(){};

    var resolve_, reject_;

    var promise = new Promise(function(resolve, reject) {
        resolve_ = resolve;
        reject_ = reject;
        fn(resolve, reject);
    });

    promise.resolve = function(val) {
        (val === undefined) ? resolve_() : resolve_(val);
        return promise;//for chainability
    }
    promise.reject = function(reason) {
        (reason === undefined) ? reject_() : reject_(reason);
        return promise;//for chainability
    }
    promise.promise = function() {
        return promise.then(); //to derive an undecorated promise (expensive but simple).
    }

    return promise;
}

単純なオブジェクトではなく装飾されたプロムジーを返すことにより、装飾に加えて、すべてのプロミスの自然なメソッド/プロパティが引き続き使用可能になります。

また、 を処理fnすることにより、Deferred で使用する必要がある場合や使用することを選択した場合に、リビーラー パターンを引き続き使用できます。

デモ

これで、Deferred()ユーティリティが配置されたので、コードは実質的に jQuery の例と同じになります。

var deferreds = {};
function waitFor(key: string): Promise<any> {
  if (key in promises) {
    return deferreds[key].promise();
  }
  var def = Deferred();    
  deferreds[key] = def;
  return def.promise();
}
于 2015-06-26T13:33:00.393 に答える