webentwicklung-frage-antwort-db.com.de

Was macht $ .when.apply ($, someArray)?

Ich bin lese über Verschobene und Versprechungen und stoße immer wieder auf $.when.apply($, someArray). Ich bin ein wenig unklar, was genau dies tut, und suche nach einer Erklärung, dass one line genau funktioniert (nicht das gesamte Code-Snippet). Hier ist etwas Kontext: 

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

.apply wird verwendet, um eine Funktion mit einem Array von Argumenten aufzurufen. Es nimmt jedes Element im Array und verwendet jedes als Parameter für die Funktion. .apply kann auch den Kontext (this) innerhalb einer Funktion ändern.

Nehmen wir also $.when. Es wird verwendet, um zu sagen "Wenn all diese Versprechen gelöst sind ... tun Sie etwas". Es benötigt unendlich viele (variable) Parameter.

In Ihrem Fall haben Sie eine Reihe von Versprechen. Sie wissen nicht, wie viele Parameter Sie an $.when übergeben. Die Übergabe des Arrays selbst an $.when würde nicht funktionieren, da es erwartet, dass seine Parameter Versprechen sind, kein Array.

Hier kommt .apply ins Spiel. Er nimmt das Array und ruft $.when mit jedem Element als Parameter auf (und stellt sicher, dass die this auf jQuery/$ gesetzt ist).

152
Rocket Hazmat

$ .when nimmt eine beliebige Anzahl von Parametern und löst auf, wenn alle aufgelöst wurden.

anyFunction .apply (thisValue, arrayParameters) ruft die Funktion anyFunction auf, die ihren Kontext setzt (dieser Wert ist der this innerhalb dieses Funktionsaufrufs) und übergibt alle Objekte in arrayParameters als einzelne Parameter.

Zum Beispiel:

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

Ist das gleiche wie:

$.when(def1, def2)

Mit der Aufrufmethode apply können Sie jedoch ein Array mit einer unbekannten Anzahl von Parametern übergeben. (In Ihrem Code sagen Sie, dass data von einem Dienst stammt, dann ist dies die einzige Möglichkeit, $ .when aufzurufen.)

61

Hier ist der Code vollständig dokumentiert.

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

Vielleicht kann jemand das nützlich finden:

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

everythingDone wird bei Ablehnung nicht gerufen

1
Vlado Kurelec

Leider kann ich euch nicht zustimmen.

$.when.apply($, processItemsDeferred).always(everythingDone);

Ruft everythingDone auf, sobald ein zurückgestellter ablehnt wird, auch wenn andere zurückgestellte pending sind.

Hier ist das vollständige Skript (ich empfehle 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');
}

Ist das ein Fehler? Ich möchte das gerne so verwenden, wie es der Herr oben beschrieben hat.

1
user3388213

$ .wenn allein der Aufruf eines Callbacks möglich ist, wenn alle an ihn übergebenen Zusagen gelöst/abgelehnt werden. Normalerweise benötigt $ .wenn eine variable Anzahl von Argumenten. Mit .apply kann ein Array von Argumenten übergeben werden. Das ist sehr mächtig. Weitere Informationen zu .apply: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply

0
Roger C

Danke für Ihre elegante Lösung: 

var promise;

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

promise.then(everythingDone);

Nur ein Punkt: Wenn Sie resolveWith verwenden, um einige Parameter abzurufen, wird der Parameter aufgrund des anfänglichen Versprechens auf undefined unterbrochen. Was ich getan habe, damit es funktioniert:

// 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