115

I'm reading about Deferreds and Promises and keep coming across $.when.apply($, someArray). I'm a little unclear on what this does exactly, looking for an explanation that one line works exactly (not the entire code snippet). Here's some context:

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');
}
4

7 に答える 7

170

.apply引数の配列を使用して関数を呼び出すために使用されます。配列内の各要素を受け取り、それぞれを関数のパラメーターとして使用します。 .apply関数内のコンテキスト(this)を変更することもできます。

だから、取りましょう$.when。これは、「これらの約束がすべて解決されたら...何かをする」と言うために使用されます。無限の(可変の)パラメーターを取ります。

あなたの場合、あなたには一連の約束があります。に渡すパラメータの数がわかりません$.when。配列自体をに渡す$.whenことは機能しません。これは、そのパラメーターが配列ではなく、promiseであると想定しているためです。

そこで登場.applyします。配列を受け取り、$.when各要素をパラメーターとして呼び出します(そして、が/thisに設定されていることを確認します)。したがって、すべてが機能します:-)jQuery$

于 2013-02-08T16:34:26.680 に答える
64

$ .whenは任意の数のパラメーターを受け取り、これらすべてが解決されたときに解決します。

anyFunction .apply(thisValue、arrayParameters)は、コンテキストを設定して関数anyFunctionを呼び出し(thisValueはその関数呼び出し内のthisになります)、arrayParameters内​​のすべてのオブジェクトを個別のパラメーターとして渡します。

例えば:

$.when.apply($, [def1, def2])

と同じです:

$.when(def1, def2)

ただし、applyの呼び出し方法では、不明な数のパラメーターの配列を渡すことができます。(あなたのコードでは、あなたはあなたのデータがサービスから来ていると言っています、そしてそれは$ .whenを呼び出す唯一の方法です)

于 2013-02-08T16:40:02.687 に答える
17

ここでは、コードが完全に文書化されています。

// 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');
}
于 2013-02-08T16:36:56.880 に答える
0

$ .whenだけで、コールバックに渡されたすべてのプロミスが解決/拒否されたときにコールバックを呼び出すことができます。通常、$。whenは可変数の引数を取りますが、.applyを使用すると、引数の配列を渡すことができ、非常に強力です。.applyの詳細については、https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/applyをご覧ください。

于 2013-02-08T16:34:35.500 に答える
0

エレガントなソリューションをありがとう:

var promise;

for(var i = 0; i < data.length; i++){
  promise = $.when(promise, processItem(data[i]));
}

promise.then(everythingDone);

1 つのポイント:resolveWithいくつかのパラメーターを取得するために使用すると、初期の promise が未定義に設定されているために壊れます。それを機能させるために私がしたこと:

// 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);
于 2016-04-21T15:58:27.007 に答える