简体   繁体   English

多个 AJAX 成功顺序

[英]Multiple AJAX success in order

I am loading a collection of blocks of data using AJAX.我正在使用 AJAX 加载一组数据块。 Each one of these blocks need to be rendered in the DOM in order, so I am requesting the first block and rendering it, then request the following and so on until the last one.这些块中的每一个都需要在 DOM 中按顺序呈现,所以我请求第一个块并呈现它,然后请求以下块,依此类推直到最后一个。 When the last one is done, a deferred object is resolved to signal another function all blocks were loaded:当最后一个完成后,一个延迟对象被解析为另一个函数,所有块都已加载:

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

However, this whole wait for the previous request to be completed can slow the process down a lot.但是,整个等待上一个请求完成会大大减慢进程的速度。

So now what I am trying to do is just fire all requests as once and let the server take as many as it can, but instead of loading each block after its corresponding request is done, I would want a block to wait until the previous one has been loaded.所以现在我想要做的只是一次触发所有请求,让服务器尽可能多地处理,但不是在相应的请求完成后加载每个块,我希望一个块等到前一个已加载。

Example: 10 requests are sent.示例:发送了 10 个请求。 We would want to render the blocks in order: 1, 2, 3, ... Let's say that the requests for the first three blocks are completed in order, so the blocks are loaded in the page as we want, but then block 5 is ready before block 4, we'd want to keep the block 5 somewhere and show it in the page only after block 4 is there, that is, after the request for block 4 is done and it has been rendered.我们希望按顺序呈现块:1, 2, 3, ... 假设前三个块的请求按顺序完成,所以块按我们想要的方式加载到页面中,然后是块 5在块 4 之前准备好了,我们希望将块 5 保留在某个地方,并仅在块 4 存在后才在页面中显示它,即在对块 4 的请求完成并已呈现之后。

My questions then are:我的问题是:

  • How can I run in parallel some functions firing the requests and other functions loading the block in the page?如何并行运行一些触发请求的函数和加载页面中块的其他函数?
  • How can I signal the function loading a particular block that the previous one is done, so it can go ahead?我如何向加载特定块的函数发出信号,表明前一个块已完成,以便它可以继续?

Also, I would need to keep the deferred logic because I still have to signal when the entire process has completed.另外,我需要保留延迟逻辑,因为我仍然需要在整个过程完成时发出信号。

The most elegant way of doing so is to use Promise.all()最优雅的方式是使用Promise.all()

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

A more rudimentary way would be to mark an int to store the completed requests or an array of Booleans which is checked after each AJAX request is complete.一种更基本的方法是标记一个int来存储已完成的请求或在每个 AJAX 请求完成后检查的Booleans数组。

You can do it as follows:你可以这样做:

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

The parameter for Promise.all() is an array of promises / deferreds. Promise.all() 的参数是一个承诺/延迟数组。 The values is an array of each promise in the array, values[0] --> resolve-value of loadBlockOneDef, ... values 是数组中每个 promise 的数组,values[0] --> resolve-value of loadBlockOneDef, ...

this ensures the immediate execution of the ajax-request but resolving in order.这确保了 ajax 请求的立即执行但按顺序解决。 It always waits for the previous Deferred to be resolved, before resolving the current one (even if the current ajax-call completes before the previous one).解析当前的延迟之前,它总是等待前一个延迟被解析(即使当前的 ajax 调用在前一个之前完成)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM