如何处理jQuery延迟数组?

如何处理jQuery延迟数组?,jquery,jquery-deferred,.when,Jquery,Jquery Deferred,.when,我有一个应用程序,它要求按特定顺序加载数据:根URL,然后是模式,最后使用各种数据对象的模式和URL初始化应用程序。当用户导航应用程序时,数据对象被加载、根据模式进行验证并显示。当用户对数据进行CRUDs时,模式提供第一次通过验证 我的初始化有问题。我使用Ajax调用获取根对象$.when(),然后创建一个承诺数组,每个模式对象一个。这很有效。我在控制台里看到了回音 然后我看到了所有模式的fetch,因此每个$.ajax()调用都有效。fetchschemas()确实返回一个承诺数组 但是,最后

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

我的初始化有问题。我使用Ajax调用获取根对象$.when(),然后创建一个承诺数组,每个模式对象一个。这很有效。我在控制台里看到了回音

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

但是,最后一个when()子句从未激发,并且“DONE”一词从未出现在控制台上。jquery-1.5的源代码似乎暗示可以将“null”作为传递给$.when.apply()的对象,因为when()将构建一个内部延迟()对象,以便在没有传递对象的情况下管理列表

这在使用Futures.js时有效。如果不是这样,那么应该如何管理jQuery延迟数组

    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);
        });
    });
你在找什么

$.when.apply($, promises).then(function(schemas) {
     console.log("DONE", this, schemas);
}, function(e) {
     console.log("My ajax failed");
});
这也会起作用(对于一些有价值的工作来说,它不会修复损坏的ajax):

您需要传递
$
而不是
null
,这样
这个
$里面。当
引用
jQuery
时。这对源代码不重要,但传递
null
更好

通过使用
$.when
和示例替换所有的$.ajax,模拟出所有的$.ajax

因此,这要么是ajax请求中的问题,要么是传递给获取模式的数组中的问题。

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

$.when.apply($, promises).then(function() {
     var schemas=arguments; // The array of resolved objects as a pseudo-array
     ...
};
因为我们传递了一系列延迟,所以返回一系列结果会很好。如果能得到一个实际数组而不是伪数组,那么我们就可以使用像
array.sort()
这样的方法

以下是一个受when.js
when.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");
});

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

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

有关ES6 spread operator的更多信息,请参见此处

使用此代码进行扩展:

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)
    }
}

非常感谢。这个语法与done().fail()有什么不同?@elf Sternberg,
。然后(a,b)==.done(a)。fail(b)
这是一个懒惰的速记。如果您想调用,$.when.apply($,…)和$.when.apply(null,…)的使用似乎无关紧要,那么可以调用
.done(a).fail(b)
。jQuery本身没有promise()方法,因此它会被忽略,取而代之的是一个内部生成的延迟对象(jQuery 1.5,第943行)。@ElfSternberg它确实不相关,但为了可读性,我不需要再看一眼
$。当.apply($,…
)时,
null
会让我问“等等,什么?”。这是一个风格和编码实践的问题。我必须阅读源代码以确认
这个
不会在jQuery中抛出null引用。当!null的使用让我想到“好的,这是一种解决方法”(事实就是这样),而如果使用了$,我的注意力就会转移到考虑$的wtf用途上。我有一个几乎相同的问题,除了在打印“完成”之前,我需要在fetch_one中为每个ajax查询启动一个“success”方法。你会怎么做?我尝试在“fetch_one”之后使用.pipe,但这似乎不起作用。@crispyduck-您是否可以100%确定then()中“schemas”变量中数组元素的顺序始终与when()中“promises”变量中的ajax调用的顺序相同?这应该被内置到jQuery中,但是-jQuery团队已经多次拒绝了这个请求。与此同时,人们不断地在这里问这个问题,并对jQuery开出类似的罚单,结果我们到处都是userland实现和/或笨拙地调用
apply()
…算了吧。感谢这个解决方案!如果一个(或多个)失败了,还有什么方法可以获得成功的项目吗?好吧,你在这里所做的就是将
参数隐藏到它自己的方法中。很好地重复使用,但并没有解决必须处理
参数的“丑陋”(您可以很容易地得到:
var schemas=Array.prototype.slice.call(arguments);)
@crispyduck,不应该
延迟。失败(…)
读取
延迟。拒绝(…)
?是的。虽然我们这些使用Coffeescript的人或其后代/模仿者已经接触到该操作员一段时间了。这比评分更高的答案更好吗?它到底起什么作用?没有解释的答案没有多大帮助。
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)
    }
}