【问题标题】:how to resolve all promises in a for loop?如何解决 for 循环中的所有承诺?
【发布时间】:2015-12-11 06:22:47
【问题描述】:

还有一个关于承诺的问题。我有这种情况:

Service.prototype.parse = function (data) {
    var deferred = $.Deferred();
    var arr      = [];
    for (var i = 0; i < data.length; i++) {
        var details = new Details();
        $.when(details).then(function (data) {
            arr.push(data);
            deferred.resolve(arr);
        });
    }

    return deferred.promise;
};

代码中的其他地方:

...
$.when(parse()).then(function (resp) {
   //...
});

promise 在某个时候得到解决,但最初 resp 的长度为 1。

如何等待parse()解决一切并返回一个数组?

【问题讨论】:

  • @Bergi 这不是重复的,它只是相似的,也许链接到它是合适的,但我认为这些问题足够遥远,可以分开。这个问题本身就很有价值。
  • @BenjaminGruenbaum:是的,但是我们有很多关于多个并发延迟的 jQuery 问题,这肯定是一个骗局 :-) 我只是还没有决定一个好的规范。
  • @Bergi 我也是,我一直在努力。问题是这些问题足够不同,没有什么是完全重复的,而且我担心向人们展示类似(但不完全相同)相同问题的类似问题可能会阻止他们。我认为从问题中链接就足够了。

标签: javascript jquery promise jquery-deferred


【解决方案1】:

请试试这个:

Service.prototype.parse = function(data) {
  var detailsArr = [];
  for (var i = 0; i < data.length; i++) {
    var details = new Details();
    detailsArr.push(details);
  }

  return $.when.apply($, detailsArr).then(function(){
    return Array.prototype.slice.call(arguments);
  });
};

这里我们将所有Details放入一个数组中,使用$.when.apply($, arr)等待所有Details得到解决。完成后,每个Details的返回数据将作为一个参数传递给回调函数,因此回调函数将接收到总共data.length个参数。然后我们使用 Array.prototype.slice.call 将所有参数转换为数组并返回结果。

供您参考:

What does $.when.apply($, someArray) do?

How can I convert the "arguments" object to an array in JavaScript?

【讨论】:

  • 这不是反模式。请注意在 OP 的问题How to wait for parse() to resolve everything and return a array? 中,返回数据类型应该是一个数组。这里使用了一个新的 Promise 将参数对象转换为数组。您的建议没有引入新的承诺,但返回数据类型与 OP 要求的不同。
  • 我不在乎你在那个回调中到底做了什么,我在乎你不必要地(并且错误地)创建一个新的$.Deferred 并从.done() 解决它,而不是仅仅使用@ 987654329@。相信我们,这是一个反模式:-)
  • 你的论点可以只是 Array.of
  • 谢谢,我从你那里学到了 Array.of,但我不想很快在我自己的项目中使用它,因为它的兼容性。如果 jQuery 中有类似的功能,我会很高兴学习和使用。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
【解决方案2】:

不需要延迟反模式(显式构造)或显式数组构造。您的代码可以简化为:

Service.prototype.parse = function (data) {
     return $.when.apply($, data.map(function(x){
         return new Details(); 
     }).then(function(){ return arguments; });//.then(Array.of); // instead, if want array
};

一些一般性建议:

  • 您忽略了您在数据中迭代的项目,我假设您不会在实际代码中这样做,而只是确保。
  • 在构造函数中执行异步 IO 是 generally not the best idea。请考虑将构造和初始化分开。
  • 您应该考虑使用原生 Promise(或库)或使用支持 non problematic promises 的 jQuery 3.0.0。

【讨论】:

  • 我认为你的建议有几个问题:1)IE 9不支持Array.map; 2) parse() 函数应该返回一个承诺,但你没有; 3) arguments 不是数组。它类似于 Array,但除了长度之外没有任何 Array 属性。 developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
  • @JMYang 请阅读stackoverflow.com/questions/23803743/…,Array.map 可以是 polyfill(或者可以使用 jQuery.map),但我不认为我的一些人支持的古老浏览器必须支持答案(除非 OP 声明如此)。
  • @JMYang 大声笑,Array.map 是你指出的? Edge 甚至不支持 Array.from。
  • @Florian Margaine 请检查developer.mozilla.org/en/docs/Web/JavaScript/Reference/…,从 IE 5.5 开始支持 Array.push。在不了解 OP 的环境要求的情况下,我认为兼容性越好。我们不必在这里使用 Array.map 对吧?此外,这不是主要问题。主要问题是#2。对于#3,如果 OP 想要对返回的数据使用任何 Array 方法,如果返回数据是参数而不是数组,他将失败。
  • @JMYang stackoverflow.com/questions/23803743/…,基本上,如果您的数组中有一个承诺错误 - 您的答案会默默地忽略失败,而不给用户任何处理它的方法。如果您解决了答案,我很乐意撤消它。我也不欣赏指控,虽然您的否决确实促使我阅读了您的答案,但这并不是导致否决的原因。
猜你喜欢
  • 1970-01-01
  • 2017-09-27
  • 2018-03-13
  • 1970-01-01
  • 2015-11-13
  • 2015-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多