【问题标题】:Deferred Promise & Jquery延迟承诺和 Jquery
【发布时间】:2014-08-15 02:17:05
【问题描述】:

我阅读了很多关于延迟的答案,但无法准确找到我想要的。

关闭的代码是http://jsfiddle.net/UZzeC/

我的代码的不同之处在于我想在 when 中调用“process”函数。语句 N 次。

//Dynamically generated JSON list
var json_list = [
    {"id":"div1","name":"Google.com"},
    {"id":"div2","name":"eBay.com"}
    {"id":"div3","name":"Yahoo.com"},
    {"id":"div4","name":"Facebook.com"}
];

$.when(
    for (var i in json_list) {
        process(json_list[i].id, json_list[i].name),
    }
).done(function() {
    $('#global').text("OK"); }
) .fail(function() {
    $('#global').text("FAIL");
});

最终状态将是异步连接到多个 Web 服务的代码,并在每个服务返回数据时返回其进度

我可以像这样嵌入这个循环吗?我在什么时候看到了“应用”的一些用法,但不确定它对我有什么用。

【问题讨论】:

  • var i in json_list 也会遍历原型的属性。
  • 使用 json_list.hasOwnProperty(i) 阻止原型属性上的调用进程
  • @agconti 它只会通过 enumerable 属性。在现代浏览器上,不会有任何不是编码员自己放在那里的。
  • 无论如何,json_list 实际上是一个数组而不是一个对象,所以代码根本不应该使用for .. in!
  • 感谢大家的贡献。为了给您更好的视觉效果,我创建了一个不太完美的 JSFiddle 示例:jsfiddle.net/b23aoe52/1

标签: javascript jquery loops promise deferred


【解决方案1】:

我认为你想做的是这样的...... (假设进程返回一个 $.Deferred().promise() 对象)

var requests = [];

for (var i=0; i<json_list.length; i++) {
    requests.push(process(json_list[i].id, json_list[i].name));
}

$.when.apply($, requests).then(
    function() { $('#global').text("OK"); },
    function() { $('#global').text("FAIL"); }
);

编辑: 编辑代码以正确迭代数组。我认为它是一个对象并用于..in,但您应该始终使用这种方式;)

【讨论】:

  • 顺便说一下,由于您使用的是 jQuery,您可以将 for..in 替换为 $.each
  • 感谢 danikaze 的快速响应!我会试试这个,但似乎这样可以解决问题。
  • @danikaze 和 FWIW,jQuery 的 .each 不 使用 hasOwnProperty 测试。
  • @Alnitak 我不了解 jQuery 的内部结构,但如果你想在使用 for..in 循环时与 IE8 兼容,则需要使用 hasOwnProperty
  • jQuery 明确记录 (somewhere) 如果 Object.prototype 已被不安全地扩展,它将无法工作。无论如何,OP 有一个数组而不是一个对象,所以根本不应该使用 for .. in!
【解决方案2】:

只有在非常特殊的情况下(实际上,从不)才应该使用for(var i in arr) {...} 来循环数组。原因是数组可能具有除数字数组索引以外的属性,即使if(arr.hasOwnProperty(i)) 也不会过滤掉。

例如:

var arr = ['A', 'B', 'C'];
arr.color = 'RED';

现在,使用for(var i in arr) 循环遍历arr,您将发现A、B、C 和RED。即数组的成员及其属性。

DEMO

为了保证只寻址数组成员,循环使用for(var i=0; i&lt;arr.length; i++) {...}。

DEMO

所以,你可以这样做:

var requests = [];
for(var i=0; i<json_list.length; i++) {
    requests.push(process(json_list[i].id, json_list[i].name));
}

$.when.apply(null, requests).then(function() {
    $('#global').text("OK");
}, function() {
    $('#global').text("FAIL");
});

您也可以使用原生的Array.prototype.map() 或jQuery.map() 循环遍历原始数组并返回处理后的数组。为了紧凑,处理后的数组可以匿名传递给$.when,如下:

$.when.apply(null, $.map(json_list, function(request) {
    return process(request.id, request.name);
}).get()).then(function() {
    $('#global').text("OK");
}, function() {
    $('#global').text("FAIL");
});

【讨论】:

  • 您确定可以将 jQuery 对象从 $.map 直接传递给 .apply 而无需先调用 .get()?
  • @Alnitak,我的错误 - 是的,.get() 是必要的,谢谢,已编辑。
  • @ChrisP 你还没有将json_list 传递到最后一个示例的代码中。
  • 是的,抱歉 Alnitak - 我没有正确完成示例,其中按钮实际正确调用函数并且正确引用了 JSON。让我看看我是否可以清理一下并再次发布更新的示例。
  • 我采纳了建议,并让新示例更加完整(不完美)jsfiddle.net/b23aoe52/3
【解决方案3】:
  1. 不要在数组上使用for .. in
  2. 您不能用 for 循环替换函数参数 - JS 不能那样工作

由于您的 json_list 是一个数组,您可以使用 .map 来获取一个新的 Promise 数组,用于原始数组中的每个条目:

var requests = json_list.map(function(l) {
    return func_returning_promise(l.id, l.name);
});

然后您可以使用 Function.prototype.apply 将这个 Promises 数组传递给 $.when,就好像它们是单独的参数一样:

$.when.apply($, requests).then(okFunc, failFunc);

【讨论】:

  • 也许值得注意的是,jQuery.map(fn) 有一个潜在的有用功能,而原生 Array.prototype.map() 缺少一个潜在的有用功能 - 即,在前者中,从 fn 返回 null 省略了从输出数组。在后者中,您会得到 member == null。因此,在您的储物柜中同时使用这两种方法很有用。
  • @Roamer-1888 我将其称为错误,而不是功能 ;-) 如果我想删除 null 项目,我会首先调用 .filter
  • 鉴于 jQuery.map 从一开始就出现在 v1.0 中,比 Array.prototype.map 在 ES 5.1 上出现的时间早了大约 5 年,我总是觉得很难看到它! (但请注意,我没有说你错了)。
  • @Roamer-1888 公平评论,但map-like 函数几十年来一直是函数式语言的主要内容,但 AFAIK 只有 jQuery 具有此“返回 null”功能。
  • 我对其他函数式语言的卓越知识表示敬意(如果重要的话,可能 APL 除外)。
猜你喜欢
  • 1970-01-01
  • 2015-03-27
  • 2023-03-21
  • 1970-01-01
  • 2014-03-10
  • 1970-01-01
  • 2015-08-25
  • 2011-07-23
相关资源
最近更新 更多