多个AJAX按顺序成功

时间:2017-01-11 08:41:54

标签: javascript ajax

我正在使用AJAX加载一组数据块。这些块中的每一个都需要按顺序在DOM中呈现,所以我请求第一个块并渲染它,然后请求以下,依此类推,直到最后一个。当最后一个完成时,解析延迟对象以发信号通知另一个函数已加载所有块:

function loadBlock(block, limit) {
  var deferred = $.Deferred();
  (function request(block, limit) {
    $.ajax({
      url: 'block/' + block,
      success: function(html) {
        $('#block-' + block).html(html);
        var nextBlock = block + 1;
        if (nextBlock <= limit)
          request(nextBlock, limit);
        else
          deferred.resolve();
      }
    });
  })(block, limit);

  return deferred.promise();
}

然而,整个等待上一个请求完成的过程可能会使该过程减慢很多。

所以现在我要做的就是将所有请求一次性激活并让服务器尽可能多地使用,但是在完成相应的请求之后不再加载每个块,我希望块等到上一个已加载。

示例:发送10个请求。我们希望按顺序渲染块:1,2,3,...让我们说前三个块的请求按顺序完成,因此块按照我们的要求加载到页面中,但是块5在块4之前准备就绪,我们想要将块5保持在某处并且仅在块4存在之后在页面中显示它,即,在块4的请求完成之后它已经呈现。

我的问题是:

  • 如何并行运行一些函数来触发请求以及在页面中加载块的其他函数?
  • 我怎样才能发出加载前一个特定区块的功能的信号,以便它可以继续?

另外,我需要保留延迟逻辑,因为我仍然需要在整个过程完成时发出信号。

3 个答案:

答案 0 :(得分:1)

最优雅的方法是使用Promise.all()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

更基本的方法是将int标记为存储已完成的请求,或者标记Booleans数组,并在每个AJAX请求完成后进行检查。

答案 1 :(得分:0)

您可以按照以下方式执行此操作:

var loadBlockOneDef = loadBlock(block, limit);
var loadBlockTwoDef = loadBlock(block, limit);
...
Promise.all([loadBlockOneDef, loadBlockTwoDef, ..])
    .then(function (values){ 
        //DO STUFF
    }

Promise.all()的参数是promises / deferreds数组。 值是数组中每个promise的数组,值[0] - &gt; loadBlockOneDef的解析值,......

答案 2 :(得分:0)

这可确保立即执行ajax-request但按顺序解析。在解析当前的之前,它始终等待先前的Deferred被解决(即使当前的ajax-call在前一个之前完成)。

var loadBlock = (function(previous){
    //the purpose of `removePreviousResponse` is to clean up 
    //the arguments returned by the Deferred
    //and to stay consistent with the behaviour of $.ajax()
    function cleanupArguments(previousArgs, currentArgs){
        //here `$.when()` is resolved with two arguments, 
        //the args for the previous and for the current ajax call
        //we want only the args for the current ajax-call to be further propagated

        //since we can not return multiple values, we wrap them into a Deferred 
        //that is resolved with multiple arguments
        var deferred = $.Deferred();
        deferred.resolve.apply(deferred, currentArgs);
        return deferred.promise();
    }

    return function(block){
        //resolves when _both_ promises are done,
        //the previous one and the current
        var current = $.when(previous, $.get('block/' + block))
            .then( cleanupArguments )
            .done(function(html, success, evt){
                //add html to the DOM
                $('#block-' + block).html(html);
            });

        previous = current;
        return current;
    }
})(null);

//the blocks are added in that order that you call `loadBlock()`
loadBlock(0);
loadBlock(1);
loadBlock(3).then(function(html, success, evt){
    //you can even append further logic
    console.log("block 3 has been loaded");
});
loadBlock(2);