132

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

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

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

但是,最后的 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);
        });
    });
4

4 回答 4

198

您正在寻找

$.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这样thisinside$.when指的是jQuery. 对来源来说应该没关系,但它比传递更好null

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

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

于 2011-02-02T19:35:47.530 回答
53

上面的解决方法(谢谢!)没有正确解决取回提供给 deferredresolve()方法的对象的问题,因为 jQuery使用单个参数而不是数组调用done()and回调。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");
});
于 2013-04-25T06:47:40.893 回答
18

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

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

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

于 2015-03-28T08:16:49.523 回答
-1

使用此代码时扩展:

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)
    }
}
于 2015-06-16T07:10:14.397 回答