【问题标题】:Using $.Deferred, promises, and $.ajax to build a dependency response map使用 $.Deferred、promises 和 $.ajax 构建依赖响应映射
【发布时间】:2015-12-05 19:58:32
【问题描述】:

我有一组需要请求的 JS 资源。必须保持顺序,并且响应必须按照我请求它们的顺序。以下请求依次请求,但我无法捕获整个请求的 .done() 承诺回调。

我从我的对象中调用 getScripts 方法:

var depArray = ['file1.js', 'file2.js', 'file3.js'];
getScripts(depArray, global_config.jspath + "/");

这会遍历 $.Deferred() 中的数组和嵌套的 $.when promise...

    getScripts : function(arr, path) {
        var depMap = [];
        $.Deferred(
            $.map(arr, function(src) {
                $.when(
                    $.ajax({
                            url: (path || "") + src + ".js",
                            success: function (data) {
                                depMap.push(data);
                                //return data;
                            }
                        }
                    )
                ).then(function() {
                    console.log("request complete...", (path || "") + src + ".js");
                    return true;
                });
            })
        ).done(
            function() { alert('completely done!!!!'); }
        );
    },

alert('completely done!!!!') 立即触发,而不是等待 ajax 调用执行并完成。我需要从方法中返回 depMap 数组,所以我有一个按顺序从调用中得到的所有响应的映射。

响应将是:

['contents from file1.js', 'contents from file2.js', 'contents from file3.js']

但我从来没有在最后交出的 depMap。 Promise 对我来说仍然有点莫名其妙。任何帮助表示赞赏...

【问题讨论】:

  • 呃,$.Deferred 没有将undefineds 数组作为参数?

标签: javascript jquery ajax dependencies promise


【解决方案1】:

$.ajax() 函数返回一个jqXHR 对象,它是一个 Promise。 $.when() 函数说它需要一个或多个 Deferred 对象,但它似乎要求它们只是 Promises,而不是完整的 Deferred 对象。因此,您不需要使用$.Deferred() 为每个ajax 请求创建Deferred 对象。您可以只使用$.ajax() 返回的对象。您可以使用$.map() 创建一个promise 数组,按照ajax 调用的顺序。

但最终,您的 getScripts() 函数无法返回 depMap 数组,因为它是异步的。相反,它可以写成返回一个 Promise,如下所示。

getScripts: function(arr, path) {
    return $.when.apply($, $.map(arr, function(src) {
        return $.ajax({ url: (path || '') + src + '.js' });
    })).then(function() {
        return (arr.length > 1)
            ? $.map(arguments, function(a) { return a[0]; })
            : [arguments[0]];
    });
},

有关从$.when(...).then() 函数返回的数组如何从其回调函数的参数构造的信息,请参阅this Stackoverflow answer。 (.done() 的相同信息适用于 .then()。)

Demo on jsfiddle

【讨论】:

    【解决方案2】:

    好的,需要进行一些清理。首先,删除$.Deferred - 因为您已经拥有$.when 承诺,所以不需要它。然后你需要构造一个promise数组并将其传递给$.when

    最后可以是这样的:

    getScripts: function(arr, path) {
        // map each promise to its resource and aggregate
        return $.when.apply(null, arr.map(function(src) {
            return $.ajax({url: (path || "") + src + ".js"});
        })).then(function(){
            return [].map.call(arguments, function(x){ return x[0]; }) // just the data
        });
    }
    

    演示: http://plnkr.co/edit/DvBj9PcaTQzskCRIUAHZ?p=preview

    【讨论】:

    • 无法保证 ajax 调用将按照它们被调用的顺序返回,因此您的答案中的代码不能保证 depMap 数组中项目的顺序。
    • 是的,很好。我最初想用真正的承诺发布答案,这就是为什么我这样写,没有为 jQuery 修复它。
    • “真正的承诺”?您指的是来自不同库的承诺吗?
    • 我的意思是真正的 Promises/A+ 投诉实现。
    • 我想强制使用 Promise 来按顺序执行 ajax 调用。一个不能在另一个之前完成。我知道你不能保证数组的顺序,但是给定一个地图.. ajax/getScript 调用需要按顺序请求。
    猜你喜欢
    • 2013-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-13
    • 2019-10-13
    • 2019-09-24
    相关资源
    最近更新 更多