$ .Deferred:すべての約束がいつ執行されたかを検出する方法

$.Deferred: How to detect when every promise has been executed


質問 written by Mister Smith @2013-10-04 13:06:33Z

: 5 : 3 : 1

私は完了する必要がある非同期タスクがいくつかあるので、私は約束を使っています。

それぞれの約束が実行された(解決されたと拒否された)両方を検出する必要があります。 それまで実行を続けてはいけません。

私はこのようなものを使っていました:

$.when(promise1, promise2, ...).always();

しかし、このコードは間違っています。whenメソッドは遅延評価をしており、約束の1つが失敗するとすぐに返されるためです。 そのため、 alwaysコールバックも、1つの約束が失敗するとすぐに実行されます。

私は回避策をコーディングすることを考えていましたが、このユースケースは非常に一般的なのですでに誰かがそれをやっているかもしれません、あるいはjQueryだけを使ってこれをする方法さえありません(そうでなければ、 Promise.whenNonLazyを追加するのはいいでしょう) Promise.when(promise1, promise2, ..., false)

これは可能ですか?

コメント 1

引数として複数の約束を持つ.when()を使用すると、それらの約束を組み合わせて実行することに関心があることになります。いずれかの約束が拒否されたwhen()when()によって返されwhen()約束は拒否されます。だから、 always() when()なくalways()があなたが観察するふるまいをしているのです。.when().always()も怠惰ではありません。どちらも完全に正しいです。どのような振る舞いをしたいのか明確ではありませんが、 when()を使用してはいけないようです。

written by ビートルート - ビートルート2013年 @2013-10-04 12:43:30Z

コメント 2

@ Beetroot-Beetrootあなたは正しい、私は質問を編集しました。しかし、私は怠惰な行動を示していると思います。

written by ミスタースミス @2013-10-04 13:08:15Z

コメント 3

なぜ「怠け者」ではなく「精力的」ではないのでしょうか。:-)

written by Beetroot-Beetroot @2013-10-04 13:25:45Z

コメント 4

それはstackoverflow.com/questions/5824615/に重複しています……動作はそこに十分に説明されています。

written by ラギバン @2015-06-15 21:33:28Z

回答 1 written by Bergi @2016-06-21 20:46:37Z
7

より洗練されたpromiseライブラリにはQようなallSettled()関数Promise.settleようなPromise.settleがあります。

jQueryでは、そのような関数を自分で実装し、それを使って$名前空間を拡張することもできますが、それが必要になるのはパフォーマンスが最適化されることが多い場合だけです。

もっと簡単な解決策は、あなたが待っているものそれぞれに新しい約束を作成し、根本的なものが拒否されたときでさえもそれらを満たすことです。 そうすれば、問題なく$.when()を使用できます。 要するに:

// using Underscore's .invoke() method:
$.when.apply(null, _.invoke(promises, "then", null, $.when)).done(…)

より安定した:

More stable:

あなたはthenコールバックをちょっと変更して、最終的な成績で達成された結果と拒否された結果を区別するかもしれません。

コメント 1

私はその考えを思いついたと思いますが、 $.Deferredは関数です。おそらく代わりに$.Deferred()が必要になるでしょう。また、成功コールバックをp.thenに渡す必要があると思います。それはエラーコールバックと同じになります。

written by スミスミスタースミス @2013-10-07 09:13:02Z

コメント 2

わかりました、その時のnull引数を理解しました。解決された約束をそのまま返すことができます。しかし、その$.Deferred必ず括弧が必要です。

written by スミスミスタースミス @2013-10-07 09:19:59Z

コメント 3

$.settle()コードを$.settle()したい場合は、ここに1つあります

written by 。stackoverflow.com/a/35820459/271351 @2017-06-01 19:06:50Z

回答 2 written by Beetroot-Beetroot @2013-10-04 14:20:02Z
1

スミー、

まず、あなたの約束が並んでいると仮定しましょう。

var promises = [....];

欲しいと.when()れるのは、これらの約束のいくつかの変換に.when()適用することです。拒否された約束は解決済みに変換され、同時に解決済みの約束に対しては透過的です。

必要な操作は次のように非常に簡潔に書くことができます。

The required operation can be written very succinctly as follows :

resolvizeは変換メカニズムです。

それで、 resolvize()はどのようになるべきでしょうか。 解決された約束と却下された約束の間の区別をするために.then()特性を活用し、それに応じて対応しましょう。

where resolvize is the transform mechanism.

未試験

何らかの外部スコープでresolvizeを使用すると、必要な場所であればどこでも$.when.apply($.map(promises, resolvize))式で使用できるようになります。 これは、jQueryを新しい方法で拡張する程度には及ばないが、ほとんどの場合適切です。

変換がどのように達成されるかにかかわらず、あなたは潜在的な問題を抱えます。 つまり、 .done()コールバックの各引数について、対応する約束が最初に解決されたのか拒否されたのかを知ることです。 それは拒否を解決に変換するために支払う代金です。 ただし、元の約束が解決または却下されたパラメータから元のステータスを検出できる場合があります。

回答 3 written by Utkanos @2013-10-04 16:14:37Z
1

これはalways興味深い性質です - 私はその振る舞いを期待していませんでした。

私はあなたが主要な据え置きの状態を監視するためにマスターの最上位の据え置きを使うことができると思います。 何かのようなもの:

//set up master deferred, to observe the states of the sub-deferreds
var master_dfd = new $.Deferred;
master_dfd.done(function() { alert('done'); });

//set up sub-deferreds
var dfds = [new $.Deferred, new $.Deferred, new $.Deferred];
var cb = function() {
    if (dfds.filter(function(dfd) {
        return /resolved|rejected/.test(dfd.state());
    }).length == dfds.length)
        master_dfd.resolve();
};
dfds.forEach(function(dfd) { dfd.always(cb); });

//resolve or reject sub-deferreds. Master deferred resolves only once
//all are resolved or rejected
dfds[0].resolve();
dfds[1].reject();
dfds[2].resolve();

フィドル: http : //jsfiddle.net/Wtxfy/3/

コメント 1

ええ、それが基本的な考え方です。私は似たようなことをしています:それぞれの遅延に対して遅延されたラッパーを作成し、含まれている遅延が解決されるか拒否されたときにラッパーを解決します。最後に、すべてのラッパーに通常の$.whenを適用します。解決されたパラメータを延期されたメインに戻す方法をまだ解決しなければなり$.when (解決された場合、 $.when約束は各約束の個々のパラメータのリストを受け取ります)。私のwhenNonLazyメソッドでも同じことをしたいのですが。

written by ミスタースミス @2013-10-04 09:49:10Z

コメント 2

.always()はコールバックを1回だけ行いますが、なぜ2回渡すのですか?

written by ベルギー、 @2013-10-04 12:52:07Z