jQuery推迟了复杂的顺序循环

时间:2016-07-11 13:15:37

标签: jquery ajax loops deferred sequential

我试图在stackoverflow上阅读很多答案,但大多数问题似乎比我的要简单一些。我想做的是:

  1. 执行一个不同长度的for循环,通过ajax查询检索表行。
  2. 一旦我获得了所有行,我想通过另一个ajax查询检索统计信息
  3. 一旦我获得了统计数据,我需要向服务器发送一条消息,该服务器执行另一个免费数据库内存调用(哦,是的,我确实与所有这些背后的某种旧式web服务进行通信)。 / LI>

    这是我的代码:

        var chainedPromise = new Array();
        //Build a .then() chain by assignment
        for (i = 0; i < requests.length; i++) {
            (function(i){
                chainedPromise = $.when().then(function(){
                    return get_results_ajax(table, idRows, requests[i-1], requests[i], type, cfg.siteroot);
                });
            })(i);
        }
    
        var Promise = $.when(chainedPromise).then(function(){
            return get_stats_ajax(table, idRows, type, cfg.siteroot);
        }).then(function() {
            return get_free_ajax(table,idRows, type, cfg.siteroot);
        });
    

    请求包含一个数字列表:[100,200,300,400],最多5000个。 每个请求应发回100个表行。这可以正常工作。

    在我检索完所有数据后执行统计和自由操作不起作用。因此,显然,最后两个调用的链接需要以不同的方式完成,但我不明白应该如何完成。

    ajax调用是这样的:

    function get_results_ajax(table, idRows, start, stop, type, siteroot) {
        var deferred = jQuery.Deferred();
        var request = jQuery.ajax({
            type        : 'POST'
            url         : siteroot+"/index.php?page=ajax",
            data        : "type="+type+"&idRows="+idRows+"&start="+start+"&stop="+stop,
            dataType    : 'json',
        });
    
        request.success(function(data) {
            table.rows.add(data).draw();
        });
    
        request.done(function(msg, textStatus, jqXHR) {
            if (jqXHR.status === 200) {
                deferred.resolve(jqXHR.responseText);
            }
            console.log("Returned data from " + start + " to " + stop);
        });
    
        request.fail(function(msg, textStatus, jqXHR) {
            console.log("The server is taking too long to respond. Start: " + start + " Stop: " + stop);
            deferred.reject("HTTP error: " + jqXHR.status);
        });
        return deferred.promise();
    }
    

1 个答案:

答案 0 :(得分:0)

首先,这里有几个错误:

var chainedPromise = new Array();
//Build a .then() chain by assignment
for (i = 0; i < requests.length; i++) {
    (function(i){
        chainedPromise = $.when().then(function(){
            return get_results_ajax(table, idRows, requests[i-1], requests[i], type, cfg.siteroot);
        });
    })(i);
}

var Promise = $.when(chainedPromise).then(function(){
    return get_stats_ajax(table, idRows, type, cfg.siteroot);
}).then(function() {
    return get_free_ajax(table,idRows, type, cfg.siteroot);
});
  1. chainedPromise是一个数组,您希望它保持为数组,以便将其传递给$.when()。要向数组添加值,请使用.push()。您只是分配给chainedPromise,它只是用新值替换它,它不再是数组。

  2. get_results_ajx()会返回一个承诺,因此您可以直接使用该承诺。无需在其前面使用$.when().then(...)

  3. $.when()不直接接受数组(如果你问我,jQuery的愚蠢设计决定),而是采用一系列单独的参数,所以要传递一个数组,你有使用.apply()将数组转换为参数列表。

  4. 当你有一个数组要处理成一组promises时,使用.map()比使用for循环要容易得多。

    < / LI>
  5. 你有一个循环,数组索引从0开始,你尝试引用requests[i-1],这将在循环的第一次迭代中给你undefined,因为i-1 === -1 。我不知道你对第一次迭代的意图。您的意思是在i = 1开始迭代吗?

  6. 因此,除了您仍然需要修复上面的第5项之外,所有初始代码都可以更改为:

    var promiseArray = requests.map(function(item, i) {
        return get_results_ajax(table, idRows, requests[i-1], requests[i], type, cfg.siteroot);
    });
    
    $.when.apply($, promiseArray).then(function() {
        return get_stats_ajax(table, idRows, type, cfg.siteroot);
    }).then(function() {
        return get_free_ajax(table,idRows, type, cfg.siteroot);
    });
    

    然后,你的get_results_ajax()使事情变得更加复杂。 jQuery&#39; s $.ajax()已经返回一个承诺。您可以直接使用它,而不需要创建自己的延迟。实际上,将其包装在另一个延迟中称为promise anti-pattern

    所以,这个:

    function get_results_ajax(table, idRows, start, stop, type, siteroot) {
        var deferred = jQuery.Deferred();
        var request = jQuery.ajax({
            type        : 'POST'
            url         : siteroot+"/index.php?page=ajax",
            data        : "type="+type+"&idRows="+idRows+"&start="+start+"&stop="+stop,
            dataType    : 'json',
        });
    
        request.success(function(data) {
            table.rows.add(data).draw();
        });
    
        request.done(function(msg, textStatus, jqXHR) {
            if (jqXHR.status === 200) {
                deferred.resolve(jqXHR.responseText);
            }
            console.log("Returned data from " + start + " to " + stop);
        });
    
        request.fail(function(msg, textStatus, jqXHR) {
            console.log("The server is taking too long to respond. Start: " + start + " Stop: " + stop);
            deferred.reject("HTTP error: " + jqXHR.status);
        });
        return deferred.promise();
    }
    

    可以成为这个:

    function get_results_ajax(table, idRows, start, stop, type, siteroot) {
        return jQuery.ajax({
            type        : 'POST'
            url         : siteroot+"/index.php?page=ajax",
            data        : "type="+type+"&idRows="+idRows+"&start="+start+"&stop="+stop,
            dataType    : 'json',
        }).then(function(data) {
            table.rows.add(data).draw();
        });
    }    
    

    我改变的事情:

    1. 直接返回jQuery.ajax()承诺。无需创建延期。
    2. 使用promise标准.then()而不是jQuery专有.done()。由于jQuery支持.then()并且它现在是ES6中的标准,所以要继续前进。
    3. 直接返回promise时,它会自动在返回的promise中传播错误。您不必手动执行此操作。