118 votes

Que fait $.when.apply($, someArray) ?

Je suis lecture sur les différés et les promesses et je continue à tomber sur $.when.apply($, someArray) . Je ne sais pas exactement ce que cela fait, je cherche une explication qui une ligne fonctionne exactement (pas l'extrait de code entier). Voici un peu de contexte :

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

1 votes

.done() peut être utilisé à la place de .then dans ce cas, juste pour info

2 votes

Pour info, il existe un portage différé de underscore qui permet de passer un tableau unique à _.when donc vous n'avez pas besoin d'utiliser apply

0 votes

172voto

Rocket Hazmat Points 87407

.apply est utilisé pour appeler une fonction avec un tableau d'arguments. Elle prend chaque élément du tableau et l'utilise comme paramètre de la fonction. .apply peut également changer le contexte ( this ) à l'intérieur d'une fonction.

Alors, prenons $.when . On l'utilise pour dire "quand toutes ces promesses seront résolues... faites quelque chose". Il prend un nombre infini (variable) de paramètres.

Dans votre cas, vous avez un tableau de promesses ; vous ne savez pas combien de paramètres vous passez à $.when . En passant le tableau lui-même à $.when ne fonctionnerait pas, car il s'attend à ce que ses paramètres soient des promesses, et non un tableau.

C'est là que .apply entre en jeu. Il prend le tableau, et appelle $.when avec chaque élément en tant que paramètre (et s'assure que l'élément this est réglé sur jQuery / $ ), alors tout fonctionne :-)

3 votes

Lorsque plusieurs promesses sont passées à la méthode $.when. Dans quel ordre seront-elles exécutées ? l'une après l'autre ou en parallèle ?

23 votes

@Darshan : On ne "court" pas les promesses. Vous attendez qu'elles soient résolues. Elles sont exécutées lorsqu'elles sont créées, $.when attend simplement qu'ils soient tous terminés avant de continuer.

3 votes

Qu'en est-il de la différence entre $.when($, arrayOfPromises).done(...) et $.when(null, arrayOfPromises).done(...) (que j'ai trouvées toutes deux comme solutions proposées dans les forums...)

69voto

$.when prend un nombre quelconque de paramètres et résout quand toutes ces questions ont été résolues.

touteFonction .apply(thisValue, arrayParameters) appelle la fonction touteFonction en définissant son contexte (thisValue sera l' este dans cet appel de fonction) et transmet tous les objets de arrayParameters comme des paramètres individuels.

Par exemple :

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

C'est la même chose que :

$.when(def1, def2)

Mais le appliquer vous permet de passer un tableau d'un nombre inconnu de paramètres. (Dans votre code, vous dites que vous données provient d'un service, alors c'est la seule façon d'appeler $.when )

17voto

Yanick Rochon Points 18537

Ici, le code est entièrement documenté.

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

7 votes

$.when.apply($, array) es no la même chose que $.when(array) . C'est la même chose que : $.when(array[0], array[1], ...)

1 votes

C'est la raison principale pour laquelle il est utilisé avec .appliquer vous ne savez pas combien d'éléments processItemsDeferred possède.

2voto

user3388213 Points 1

Malheureusement, je ne peux pas être d'accord avec vous.

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

Appellation everythingDone dès qu'un différé est obtenu rejeté même s'il y a d'autres différés qui sont en attente de .

Voici le script complet (Je recommande 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');
}

C'est un bug ? J'aimerais l'utiliser comme le monsieur ci-dessus l'a décrit.

1 votes

Le premier rejet va tirer le always, mais pas le .then. Voir mon jsfiddle.net/logankd/s5dacgb3 que j'ai fait à partir de votre exemple. J'utilise JQuery 2.1.0 dans cet exemple.

1 votes

C'est comme prévu. Il y a une tonne de cas où vous voudriez savoir dès que quelque chose échoue, et non pas attendre que tout soit terminé et vérifier s'il y a eu des échecs. En particulier si le traitement ne peut pas continuer après un échec, pourquoi attendre que le reste se termine / échoue ? Comme le suggère l'autre commentaire, vous pouvez utiliser la paire .then ou .fail & .done.

0 votes

@GoneCoding Ce n'est pas utile. L'OP a demandé ce que faisait la fonction apply() et vous avez suggéré une alternative terrible qui ne devrait jamais être utilisée :) c'est à cela que sert le bouton de vote négatif. Je ne l'ai pas non plus utilisé jusqu'à ce que vous refusiez de fournir la raison pour laquelle vous l'avez fait (plus que votre préférence pour éviter les tableaux pour une raison quelconque).

0voto

Roger C Points 280

$.when permet à lui seul d'appeler une callback lorsque toutes les promesses qui lui sont passées sont résolues/rejetées. Normalement, $.when prend un nombre variable d'arguments, l'utilisation de .apply permet de lui passer un tableau d'arguments, c'est très puissant. Pour plus d'informations sur .apply : https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X