私は DeferredsとPromisesについて読んでいます で、$.when.apply($, someArray)
に出会っています。 1行が正確に機能する(コード全体ではなく)という説明を探して、これが正確に何をするのか少しわかりません。コンテキストは次のとおりです。
var data = [1,2,3,4]; // the ids coming back from serviceA
var processItemsDeferred = [];
for(var i = 0; i < data.length; i++){
processItemsDeferred.Push(processItem(data[i]));
}
$.when.apply($, processItemsDeferred).then(everythingDone);
function processItem(data) {
var dfd = $.Deferred();
console.log('called processItem');
//in the real world, this would probably make an AJAX call.
setTimeout(function() { dfd.resolve() }, 2000);
return dfd.promise();
}
function everythingDone(){
console.log('processed all items');
}
.apply
は、引数の配列で関数を呼び出すために使用されます。配列内の各要素を受け取り、それぞれを関数へのパラメーターとして使用します。 .apply
は、関数内のコンテキスト(this
)も変更できます。
それでは、$.when
を見てみましょう。 「これらの約束がすべて解決されると...何かをする」と言われます。パラメーターの数は無限(可変)になります。
あなたの場合、約束の配列があります。 $.when
に渡すパラメーターの数がわかりません。配列自体を$.when
に渡すと機能しません。これは、配列ではなくパラメーターがpromiseであると想定しているためです。
それが.apply
の出番です。配列を受け取り、各要素をパラメーターとして$.when
を呼び出します(そして、this
がjQuery
/$
に設定されていることを確認します)。
$。when は任意の数のパラメーターを取り、解決しますwhenこれらはすべて解決しました。
anyFunction。apply(thisValue、arrayParameters)は、関数を呼び出しますanyFunctionその設定コンテキスト(thisValueはその関数呼び出し内でthisになります)、arrayParametersのすべてのオブジェクトを個別のパラメーターとして渡します。
例えば:
$.when.apply($, [def1, def2])
次と同じです:
$.when(def1, def2)
ただし、applyを呼び出す方法では、不明な数のパラメーターの配列を渡すことができます。 (あなたのコードでは、あなたはdataはサービスから来ていると言っているので、それが唯一の呼び出し方法です$。when)
ここでは、コードが完全に文書化されています。
// 1. Declare an array of 4 elements
var data = [1,2,3,4]; // the ids coming back from serviceA
// 2. Declare an array of Deferred objects
var processItemsDeferred = [];
// 3. For each element of data, create a Deferred Push push it to the array
for(var i = 0; i < data.length; i++){
processItemsDeferred.Push(processItem(data[i]));
}
// 4. WHEN ALL Deferred objects in the array are resolved THEN call the function
// Note : same as $.when(processItemsDeferred[0], processItemsDeferred[1], ...).then(everythingDone);
$.when.apply($, processItemsDeferred).then(everythingDone);
// 3.1. Function called by the loop to create a Deferred object (data is numeric)
function processItem(data) {
// 3.1.1. Create the Deferred object and output some debug
var dfd = $.Deferred();
console.log('called processItem');
// 3.1.2. After some timeout, resolve the current Deferred
//in the real world, this would probably make an AJAX call.
setTimeout(function() { dfd.resolve() }, 2000);
// 3.1.3. Return that Deferred (to be inserted into the array)
return dfd.promise();
}
// 4.1. Function called when all deferred are resolved
function everythingDone(){
// 4.1.1. Do some debug trace
console.log('processed all items');
}
残念ながら、私はあなたたちに同意できません。
$.when.apply($, processItemsDeferred).always(everythingDone);
pendingである他の遅延オブジェクトがある場合でも、1つの遅延オブジェクトがrejectedになるとすぐにeverythingDone
を呼び出します。
完全なスクリプトは次のとおりです( http://jsfiddle.net/ をお勧めします):
var data = [1,2,3,4]; // the ids coming back from serviceA
var processItemsDeferred = [];
for(var i = 0; i < data.length; i++){
processItemsDeferred.Push(processItem(data[i]));
}
processItemsDeferred.Push($.Deferred().reject());
//processItemsDeferred.Push($.Deferred().resolve());
$.when.apply($, processItemsDeferred).always(everythingDone);
function processItem(data) {
var dfd = $.Deferred();
console.log('called processItem');
//in the real world, this would probably make an AJAX call.
setTimeout(function() { dfd.resolve(); }, 2000);
return dfd.promise();
}
function everythingDone(){
alert('processed all items');
}
これはバグですか?上記の紳士のようにこれを使用したいと思います。
たぶん誰かがこれを役に立つと思うかもしれません:
$.when.apply($, processItemsDeferred).then(everythingDone).fail(noGood);
everythingDoneは、リジェクトの場合には呼び出されません
$ .whenだけでは、渡されたすべてのプロミスが解決/拒否されたときにコールバックを呼び出すことができます。通常、$。whenは可変数の引数を取ります。applyを使用すると、引数の配列を渡すことができ、非常に強力です。 .applyの詳細: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply
エレガントなソリューションをありがとう:
var promise;
for(var i = 0; i < data.length; i++){
promise = $.when(promise, processItem(data[i]));
}
promise.then(everythingDone);
ただ1つのポイント:resolveWith
を使用して一部のパラメーターを取得する場合、初期プロミスが未定義に設定されているため、壊れます。私がそれを機能させるためにしたこと:
// Start with an empty resolved promise - undefined does the same thing!
var promise;
for(var i = 0; i < data.length; i++){
if(i==0) promise = processItem(data[i]);
else promise = $.when(promise, processItem(data[i]));
}
promise.then(everythingDone);