$.when.apply($, someArray) 有什么作用?

IT技术 javascript jquery asynchronous promise
2021-01-14 17:33:10

我正在阅读有关 Deferreds 和 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');
}
6个回答

.apply用于调用带有参数数组的函数。它获取数组中的每个元素,并将每个元素用作函数的参数。 .apply还可以更改this函数内的上下文 ( )。

所以,让我们拿$.when. 它习惯于说“当所有这些Promise都得到解决时……做点什么”。它需要无限(可变)数量的参数。

就您而言,您有一系列Promise;你不知道你传递了多少参数$.when将数组本身传递给它是$.when行不通的,因为它期望它的参数是 promise,而不是数组。

这就是.apply进来的地方。它接受数组,并$.when以每个元素作为参数进行调用(并确保将this其设置为jQuery/ $),然后一切正常:-)

$.when($, arrayOfPromises).done(...)之间的区别呢 $.when(null, arrayOfPromises).done(...) (我在论坛中发现它们都是建议的解决方案......)
2021-04-06 17:33:10
当多个 promise 传递给 $.when 方法时。他们将按什么顺序执行?一个接一个还是并行?
2021-04-10 17:33:10
@Darshan:你不“运行”Promise。你等着他们解决。它们在创建时执行,$.when只需等待它们全部完成后再继续。
2021-04-10 17:33:10

$.when接受任意数量的参数并所有这些都解析后解析。

anyFunction .apply(thisValue, arrayParameters) 调用函数anyFunction设置其上下文(thisValue 将是该函数调用中this)并将 arrayParameters 中的所有对象作为单独的参数传递。

例如:

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

是相同的:

$.when(def1, def2)

但是apply调用方式允许您传递一组未知数量的参数。(在您的代码中,您是说您的数据来自服务,那么这是调用$.when的唯一方法

在这里,代码完全记录。

// 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');
}
$.when.apply($, array)一样的$.when(array)它与以下相同:$.when(array[0], array[1], ...)
2021-03-17 17:33:10
这就是为什么与.apply一起使用的主要原因,你不知道 processItemsDeferred 有很多元素
2021-03-26 17:33:10

不幸的是,我不能同意你们的看法。

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

everythingDone在一个 deferred 被拒绝后立即调用,即使还有其他 deferred待处理

这是完整的脚本(我推荐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');
}

这是一个错误吗?我想像上面那位先生描述的那样使用它。

第一个拒绝将触发 always,但不会触发 .then。请参阅我根据您的示例制作的jsfiddle.net/logankd/s5dacgb3我在这个例子中使用 JQuery 2.1.0。
2021-03-13 17:33:10
这是预期的。有一吨,你会想尽快知道的情况下的东西失败了,没有等到一切完成,并检查是否有故障。特别是如果处理在任何失败后都无法继续,为什么要等待其余的完成/失败?正如另一条评论所建议的那样,您可以使用 .then 或 .fail & .done 对。
2021-03-17 17:33:10
@GoneCoding 哈哈,我阅读了您的解决方案并提供了反馈。您没有提供原始问题的答案。你无法详细说明为什么会这样。正是像您这样的人为正在学习的人提供了糟糕的解决方案。您显然具有有限的 javascript 技能,并且将我视为 n00b。我指出了为什么它错了,你甚至无法阅读代码,而是告诉我我错了。干得好伙计!
2021-04-03 17:33:10
@GoneCoding 它没有用。OP 询问了 apply() 的作用,您提出了一个永远不应该使用的糟糕替代方案:) 这就是向下投票按钮的用途。我也没有使用它,直到你拒绝提供为什么你这样做的原因(不仅仅是出于某种原因你更喜欢避免使用数组)
2021-04-05 17:33:10
@GoneCoding 感谢您取消该答案
2021-04-12 17:33:10

也许有人会发现这很有用:

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

如果有任何拒绝,则不会调用everythingDone