【问题标题】:What does $.when.apply($, someArray) do?$.when.apply($, someArray) 是做什么的?
【发布时间】:2019-01-14 21:12:32
【问题描述】:

我是reading about Deferreds and Promises,并且经常遇到$.when.apply($, someArray)。我有点不清楚这到底是做什么的,正在寻找 一行 完全有效的解释(不是整个代码 sn-p)。这是一些上下文:

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

【问题讨论】:

标签: javascript jquery asynchronous promise


【解决方案1】:

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

那么,让我们以$.when 为例。它用于说“当所有这些承诺都得到解决时......做某事”。它需要无限(可变)数量的参数。

在您的情况下,您有一系列承诺;您不知道要传递给$.when 的参数数量。将数组本身传递给 $.when 是行不通的,因为它希望它的参数是 promise,而不是数组。

这就是 .apply 出现的地方。它接受数组,并以每个元素作为参数调用 $.when(并确保将 this 设置为 jQuery/$),然后它所有作品:-)

【讨论】:

  • 当多个 Promise 被传递给 $.when 方法时。他们将以什么顺序执行?一个接一个还是并行?
  • @Darshan:你不会“运行”承诺。你等待他们解决。它们在创建时执行,$.when 只是等待它们全部完成后再继续。
  • $.when($, arrayOfPromises).done(...)$.when(null, arrayOfPromises).done(...) 之间的区别是什么(我在论坛中发现两者都是建议的解决方案...)
【解决方案2】:

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

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

例如:

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

等同于:

$.when(def1, def2)

但是 apply 的调用方式允许你传递一个未知数量的参数数组。 (在您的代码中,您是说您 data 来自服务,那么这是调用 $.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');
    }
    

    【讨论】:

    • $.when.apply($, array)$.when(array)相同。等同于:$.when(array[0], array[1], ...)
    • 这就是为什么与 .apply 一起使用的主要原因,你不知道 processItemsDeferred 有很多元素
    【解决方案4】:

    很遗憾,我不能同意你们的看法。

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

    一旦有一个延期被拒绝,将立即致电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');
    }
    

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

    【讨论】:

    • 第一个拒绝会触发always,但不会触发.then。请参阅我根据您的示例制作的jsfiddle.net/logankd/s5dacgb3。我在这个例子中使用的是 JQuery 2.1.0。
    • 这符合预期。在很多情况下,您都想在 something 失败时立即了解,而不是等待一切都完成并检查是否有失败。特别是如果处理在任何失败后无法继续,为什么要等待其余的完成/失败?正如其他评论所建议的那样,您可以使用 .then 或 .fail & .done 对。
    • @GoneCoding 没用。 OP 询问 apply() 的作用,您提出了一个永远不应该使用的可怕替代方案:) 这就是否决投票按钮的用途。我也没有使用它,直到您拒绝提供您为什么这样做(不仅仅是出于某种原因您更喜欢避免使用数组)
    • @GoneCoding 感谢您记下这个答案
    • @GoneCoding 大声笑,我阅读了您的解决方案并提供了反馈。您没有提供原始问题的答案。你无法详细说明为什么会这样。像你这样的人为正在学习的人提供了糟糕的解决方案。你显然只有有限的 javascript 技能,并且正在让我成为 n00b。我指出了错误的原因,您甚至无法阅读代码,而是告诉我我错了。干得好,伙计!
    【解决方案5】:

    也许有人会觉得这很有用:

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

    everythingDone 在任何拒绝的情况下都不会被调用

    【讨论】:

      【解决方案6】:

      $.when 单独使得当传递给它的每个承诺都被解决/拒绝时调用回调成为可能。通常, $.when 接受可变数量的参数,使用 .apply 可以将参数数组传递给它,它非常强大。有关 .apply 的更多信息:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply

      【讨论】:

        【解决方案7】:

        感谢您优雅的解决方案:

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

        只有一点:当使用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);
        

        【讨论】:

        • 虽然这确实有效,但它并不是很优雅。您正在创建代表最多延迟完成的承诺,以便最后一次迭代包含“when(workToDo[0..i-1], workToDo[i])”或更明确地说“当所有以前的工作和这个工作已经完成”。这意味着当包装你的承诺时你有 i + 1 。此外,在做这种事情时,只需打开第一次迭代。 var promise = processItem(数据[0]); for(var i = 1; i
        猜你喜欢
        • 2013-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-16
        相关资源
        最近更新 更多