web-dev-qa-db-ja.com

$ .when.apply($、someArray)は何をしますか?

私は 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');
}
105
manafire

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

それでは、$.whenを見てみましょう。 「これらの約束がすべて解決されると...何かをする」と言われます。パラメーターの数は無限(可変)になります。

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

それが.applyの出番です。配列を受け取り、各要素をパラメーターとして$.whenを呼び出します(そして、thisjQuery/$に設定されていることを確認します)。

157
Rocket Hazmat

$。when は任意の数のパラメーターを取り、解決しますwhenこれらはすべて解決しました。

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

例えば:

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

次と同じです:

$.when(def1, def2)

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

62
Pablo

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

// 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');
}
14
Yanick Rochon

残念ながら、私はあなたたちに同意できません。

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

これはバグですか?上記の紳士のようにこれを使用したいと思います。

2
user3388213

たぶん誰かがこれを役に立つと思うかもしれません:

$.when.apply($, processItemsDeferred).then(everythingDone).fail(noGood);

everythingDoneは、リジェクトの場合には呼び出されません

1
Vlado Kurelec

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

0
Roger C

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

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);
0
user3544352