Что делает $.when.apply($, someArray)?
Я читаю о Отложенных и Promises и продолжаю встречаться $.when.apply($, someArray)
. Я немного не понимаю, что именно это делает, ища объяснение, что одна строка работает точно (не весь фрагмент кода). Вот какой контекст:
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
.apply
используется для вызова функции с массивом аргументов. Он принимает каждый элемент в массиве и использует каждый в качестве параметра для функции. .apply
также может изменять контекст (this
) внутри функции.
Итак, возьмите $.when
. Раньше говорилось "когда все эти promises разрешены... что-то делать". Он принимает бесконечное (переменное) количество параметров.
В вашем случае у вас есть массив promises; вы не знаете, сколько параметров вы переходите в $.when
. Передача самого массива в $.when
не будет работать, поскольку он ожидает, что его параметры будут promises, а не массивом.
То, что входит .apply
. Он принимает массив и вызывает $.when
с каждым элементом в качестве параметра (и гарантирует, что значение this
установлено на jQuery
/$
), так что тогда все работы: -)
Ответ 2
$. когда принимает любое количество параметров и решает, когда все они разрешены.
anyFunction.apply(thisValue, arrayParameters) вызывает функцию anyFunction, устанавливающую ее контекст (thisValue будет это) и все параметры в параметрах arrayParameters.
Например:
$.when.apply($, [def1, def2])
То же, что и:
$.when(def1, def2)
Но применяемый способ вызова позволяет передать массив неизвестного числа параметров. (В вашем коде вы говорите, что данные поступают из службы, то это единственный способ вызвать $.when)
Ответ 3
Здесь код полностью задокументирован.
// 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');
}
Ответ 4
К сожалению, я не могу согласиться с вами, ребята.
$.when.apply($, processItemsDeferred).always(everythingDone);
Вызовите everythingDone
, как только один отложенный получит отклонен, даже если есть другие отложенные ожидающие.
Вот полный script (рекомендую 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');
}
Это ошибка? Я хотел бы использовать это, как описанный выше джентльмен.
Ответ 5
$, когда только позволяет вызвать обратный вызов, когда каждый переданный ему promises разрешен/отклонен. Обычно, $.when принимает переменное количество аргументов, использование .apply позволяет передать ему массив аргументов, это очень мощный. Для получения дополнительной информации о .apply: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply
Ответ 6
Спасибо за ваше элегантное решение:
var promise;
for(var i = 0; i < data.length; i++){
promise = $.when(promise, processItem(data[i]));
}
promise.then(everythingDone);
Только одно: при использовании resolveWith
для получения некоторых параметров он прерывается из-за первоначального обещания, установленного на undefined. Что я сделал, чтобы заставить его работать:
// 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);