你如何使用一组jQuery Deferreds?

Elf*_*erg 132 jquery jquery-deferred .when

我有一个应用程序需要按特定顺序加载数据:根URL,然后是模式,然后最终使用各种数据对象的模式和URL初始化应用程序.当用户导航应用程序时,将加载数据对象,根据模式进行验证并显示.当用户CRUD数据时,模式提供首次通过验证.

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

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

但是,最终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);
        });
    });
Run Code Online (Sandbox Code Playgroud)

Ray*_*nos 198

您正在寻找

$.when.apply($, promises).then(function(schemas) {
     console.log("DONE", this, schemas);
}, function(e) {
     console.log("My ajax failed");
});
Run Code Online (Sandbox Code Playgroud)

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

$.when.apply($, promises).done(function() { ... }).fail(function() { ... });` 
Run Code Online (Sandbox Code Playgroud)

你要传递$的,而不是nullthis里面$.whenjQuery.它应该对来源无关紧要,但它比传递更好null.

通过替换它们来模拟所有$ .ajax $.when并且示例正常工作

所以这是你的ajax请求中的一个问题,或者你传递给fetch_schemas的数组.

  • null的使用让我觉得'好吧,这是一种解决方法'(它就是这样),而如果使用$,我的注意力将被转移到考虑$为的wtf. (7认同)
  • @elf Sternberg,`.then(a,b)=== .done(a).fail(b)`这是一个懒惰的速记.如果你愿意,可以调用`.done(a).fail(b)` (2认同)

cri*_*uck 53

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

$.when.apply($, promises).then(function() {
     var schemas=arguments; // The array of resolved objects as a pseudo-array
     ...
};
Run Code Online (Sandbox Code Playgroud)

由于我们传入了一个延迟数组,因此返回一组结果会很好.回到实际的数组而不是伪数组也是很好的,所以我们可以使用类似的方法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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以简单地传入一个deferreds/promises数组,并在你的回调函数中找回一系列已解析/被拒绝的对象,如下所示:

$.when.all(promises).then(function(schemas) {
     console.log("DONE", this, schemas); // 'schemas' is now an array
}, function(e) {
     console.log("My ajax failed");
});
Run Code Online (Sandbox Code Playgroud)

  • 这应该只是内置到jQuery中,但是 - jQuery团队多次拒绝了这个请求.与此同时,人们不断在这里提出问题,并打开针对jQuery的类似票据,我们最终到处都是用户态实现和/或尴尬地调用`apply()`... go figure. (6认同)
  • @crispyduck,不应该'deferred.fail(...)`读`deferred.reject(...)`? (2认同)

pas*_*lus 18

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

$.when(...promises).then(function() {
 var schemas=arguments; 
};
Run Code Online (Sandbox Code Playgroud)

更多关于ES6蔓延运营商https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator发现这里