你如何使用 jQuery Deferreds 数组? [复制]

Posted

技术标签:

【中文标题】你如何使用 jQuery Deferreds 数组? [复制]【英文标题】:How do you work with an array of jQuery Deferreds? [duplicate] 【发布时间】:2011-06-20 05:12:12 【问题描述】:

我有一个应用程序需要按特定顺序加载数据:根 URL,然后是模式,最后使用各种数据对象的模式和 url 初始化应用程序。当用户浏览应用程序时,数据对象被加载、根据模式验证并显示。当用户对数据进行 CRUD 时,模式提供了首次验证。

我在初始化时遇到问题。我使用Ajax 调用来获取根对象$.when(),然后创建一个promise 数组,每个schema 对象一个promise。这样可行。我在控制台中看到了 fetch。

然后我会看到所有模式的提取,因此每个 $.ajax() 调用都有效。 fetchschemas() 确实返回了一个 promise 数组。

但是,最后的 when() 子句永远不会触发,并且“DONE”一词永远不会出现在控制台上。 jquery-1.5 的源代码似乎暗示“null”作为传递给 $.when.apply() 的对象是可接受的,因为当没有对象时 when() 将构建一个内部 Deferred() 对象来管理列表进来了。

这使用 Futures.js 有效。如果不是这样,应该如何管理 jQuery Deferreds 数组?

    var fetch_schemas, fetch_root;

    fetch_schemas = function(schema_urls) 
        var fetch_one = function(url) 
            return $.ajax(
                url: url,
                data: ,
                contentType: "application/json; charset=utf-8",
                dataType: "json"
            );
        ;

        return $.map(schema_urls, fetch_one);
    ;

    fetch_root = function() 
        return $.ajax(
            url: BASE_URL,
            data: ,
            contentType: "application/json; charset=utf-8",
            dataType: "json"
        );
    ;

    $.when(fetch_root()).then(function(data) 
        var promises = fetch_schemas(data.schema_urls);
        $.when.apply(null, promises).then(function(schemas) 
            console.log("DONE", this, schemas);
        );
    );

【问题讨论】:

我有一个几乎相同的问题,除了我需要在打印“DONE”之前为 fetch_one 中的每个 ajax 查询触发一个“成功”方法。你会怎么做呢?我尝试在“fetch_one”之后使用 .pipe,但这似乎不起作用。 【参考方案1】:

你正在寻找

$.when.apply($, promises).then(function(schemas) 
     console.log("DONE", this, schemas);
, function(e) 
     console.log("My ajax failed");
);

这也可以(对于某些工作价值,它不会修复损坏的 ajax):

$.when.apply($, promises).done(function()  ... ).fail(function()  ... );` 

您需要传递$ 而不是null,以便$.when 中的this 引用jQuery。与源无关,但最好传递null

通过用$.when 和示例works 替换它们来模拟你所有的$.ajax

所以这要么是您的 ajax 请求中的问题,要么是您传递给 fetch_schemas 的数组。

【讨论】:

谢谢。这个语法与 done().fail() 有什么不同? @elf Sternberg, .then(a,b) === .done(a).fail(b) 这是一个懒惰的速记。如果您愿意,可以致电.done(a).fail(b) 哦,$.when.apply($, ...) 和 $.when.apply(null, ...) 的使用似乎无关紧要。 jQuery 本身没有 promise() 方法,因此它被忽略以支持内部生成的 Deferred 对象(jQuery 1.5,第 943 行)。 @ElfSternberg 这确实无关紧要,但为了便于阅读,我不需要再看$.when.apply($, ...null 让我“等等,什么?”。这是风格和编码实践的问题。我必须阅读源代码以确认 this 不会在 jQuery.when 中抛出空引用! null 的使用让我觉得“好吧,这是一种解决方法”(确实如此),而如果使用 $,我的注意力会转移到考虑 $ 的用途。 【参考方案2】:

上面的解决方法(谢谢!)没有正确解决取回提供给 deferred 的 resolve() 方法的对象的问题,因为 jQuery 使用单独的参数而不是数组调用 done()fail() 回调。这意味着我们必须使用arguments 伪数组来获取延迟数组返回的所有已解决/拒绝的对象,这很难看:

$.when.apply($, promises).then(function() 
     var schemas=arguments; // The array of resolved objects as a pseudo-array
     ...
;

既然我们传入了一个延迟数组,那么返回一个结果数组会很好。取回一个实际数组而不是伪数组也很好,这样我们就可以使用像Array.sort() 这样的方法。

这是一个受 when.jswhen.all() 方法启发的解决方案,可以解决这些问题:

// Put somewhere in your scripting environment
if (jQuery.when.all===undefined) 
    jQuery.when.all = function(deferreds) 
        var deferred = new jQuery.Deferred();
        $.when.apply(jQuery, deferreds).then(
            function() 
                deferred.resolve(Array.prototype.slice.call(arguments));
            ,
            function() 
                deferred.fail(Array.prototype.slice.call(arguments));
            );

        return deferred;
    

现在您可以简单地传入一个延迟/承诺数组,并在回调中取回一个已解决/拒绝的对象数组,如下所示:

$.when.all(promises).then(function(schemas) 
     console.log("DONE", this, schemas); // 'schemas' is now an array
, function(e) 
     console.log("My ajax failed");
);

【讨论】:

@crispyduck - 你知道你是否可以 100% 确定 then() 中“模式”变量中数组元素的顺序将始终与 ajax 调用的顺序相同when() 中的“promises”变量? 这应该只是内置在 jQuery 中,但是 - jQuery 团队已经多次拒绝该请求。与此同时,人们不断在这里提出问题并针对 jQuery 打开类似的票证,我们最终得到了一个到处都是用户空间的实现和/或对apply() 的尴尬调用......去看看。 感谢您的解决方案!如果一个(或多个)失败了,有没有办法获得成功的项目? 好吧,你在这里所做的一切都是隐藏arguments 操作到它自己的方法中。非常适合重复使用,但不能解决必须处理 arguments 的“丑陋”(您可以轻松地拥有:var schemas=Array.prototype.slice.call(arguments);) @crispyduck,不应该把deferred.fail(...)读成deferred.reject(...)吗?【参考方案3】:

如果您使用的是 ES6 版本的 javascript,有一个扩展运算符 (...) 可以将对象数组转换为逗号分隔的参数。

$.when(...promises).then(function() 
 var schemas=arguments; 
;

更多关于 ES6 扩展运算符https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator 在这里找到

【讨论】:

是的。尽管我们这些使用 Coffeescript 或其后代/模仿者之一的人现在已经可以使用该运算符一段时间了。【参考方案4】:

使用此代码时扩展:

var rawWhen = $.when
$.when = function(promise) 
    if ($.isArray(promise)) 
        var dfd = new jQuery.Deferred()
        rawWhen.apply($, promise).done(function() 
            dfd.resolve(Array.prototype.slice.call(arguments))
        ).fail(function() 
            dfd.reject(Array.prototype.slice.call(arguments))
        )
        return dfd.promise()
     else 
        return rawWhen.apply($, arguments)
    

【讨论】:

这比评分更高的答案更好吗?它究竟是做什么的?没有解释的答案不是很有帮助。

以上是关于你如何使用 jQuery Deferreds 数组? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

JQuery when() done() then()

$.when()方法翻译

如何在jquery中使用php数组

$('h1') 如何在 jQuery 中作为数组记录到 Web 控制台?

如何将 HTML 表转换为 jQuery 键值对数组?

如何将 jquery 数组传递给 laravel 控制器