使用 jQuery 的并行异步 Ajax 请求

IT技术 javascript jquery ajax
2021-01-23 16:12:23

我想根据多个 ajax/json 请求的结果更新页面。使用 jQuery,我可以“链接”回调,就像这个非常简单的精简示例:

$.getJSON("/values/1", function(data) {
  // data = {value: 1}
  var value_1 = data.value;

  $.getJSON("/values/2", function(data) {
    // data = {value: 42}
    var value_2 = data.value;

    var sum = value_1 + value_2;

    $('#mynode').html(sum);
  });

});

但是,这会导致请求按顺序进行。我更喜欢一种并行发出请求的方法,并在完成后执行页面更新。有没有办法做到这一点?

6个回答

jQuery $.when()$.done()正是您所需要的:

$.when($.ajax("/page1.php"), $.ajax("/page2.php"))
  .then(myFunc, myFailure);
无意冒犯,但这个答案是不是远远优于@yehuda-katz 的答案?(鉴于这有效)
2021-03-16 16:12:23
这个答案并不清楚在 ajax 调用完成后如何访问数据。传递给 myFunc 的内容以及如何访问调用?
2021-03-17 16:12:23
示例与 myFunc 和 myFailure => codepen.io/jacobgoh101/pen/YaJOzx?editors=0010
2021-04-08 16:12:23
+1 我听说在某处Promise写得不好......显然我需要忘记这一点!
2021-04-11 16:12:23

试试这个解决方案,它可以支持任何特定数量的并行查询:

var done = 4; // number of total requests
var sum = 0;

/* Normal loops don't create a new scope */
$([1,2,3,4,5]).each(function() {
  var number = this;
  $.getJSON("/values/" + number, function(data) {
    sum += data.value;
    done -= 1;
    if(done == 0) $("#mynode").html(sum);
  });
});
看起来“if”中的代码可以执行多次。另外,“done -= 1”是原子的吗?
2021-03-22 16:12:23
好书!你的名字让我的脑海里响起了警报!
2021-03-28 16:12:23
我做过类似的事情。最后,我确实巩固了我的要求。但是为了以防万一,最好知道如何执行此操作。我显示了一个进度条,在这种情况下效果很好,因为代码是回调驱动的。在这种情况下,只需使用 100*((4-done)/4) 作为完成百分比。
2021-03-29 16:12:23
如果我没记错的话,您是 'jQuery In Action' 的作者吗?
2021-04-06 16:12:23
我使用了类似于你和agilefall的东西:var results = {}; 无功请求 = 0; var urls = ["values/1", "values/2", "values/3"]; $.each(urls, function(url) { $.getJSON(url, function(data) { results[url] = data.value; ++requests; if (requests == 3) { $('#mynode') .html( 结果[urls[0]] / 结果[urls[1]] * 结果[urls[2]]); } }); });
2021-04-11 16:12:23

并行运行多个 AJAX 请求

使用 API 时,有时需要向不同的端点发出多个 AJAX 请求。无需等待一个请求完成后再发出下一个请求,您可以通过使用 jQuery 的$.when()函数并行请求数据来使用 jQuery 加快处理速度

JS

$.when($.get('1.json'), $.get('2.json')).then(function(r1, r2){
   console.log(r1[0].message + " " + r2[0].message);
});

当这两个 GET 请求成功完成时,将执行回调函数。$.when()接受两次$.get()调用返回的Promise,并构造一个新的Promise对象。回调r1r2参数是数组,其第一个元素包含服务器响应。

这是我尝试直接解决您的问题

基本上,您只需建立 AJAX 调用堆栈,执行它们,并在所有事件完成后调用提供的函数 - 提供的参数是所有提供的 ajax 请求的结果数组。

显然,这是早期的代码 - 您可以在灵活性方面对此进行更详细的说明。

<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>
<script type="text/javascript">

var ParallelAjaxExecuter = function( onComplete )
{
  this.requests = [];
  this.results = [];
  this.onComplete = onComplete; 
}

ParallelAjaxExecuter.prototype.addRequest = function( method, url, data, format )
{
  this.requests.push( {
      "method"    : method
    , "url"       : url
    , "data"      : data
    , "format"    : format
    , "completed" : false
  } )
}

ParallelAjaxExecuter.prototype.dispatchAll = function()
{
  var self = this;
  $.each( self.requests, function( i, request )
    {
    request.method( request.url, request.data, function( r )
    {
      return function( data )
      {
        console.log
        r.completed = true;
        self.results.push( data );
        self.checkAndComplete();
      }
    }( request ) )
  } )
}

ParallelAjaxExecuter.prototype.allRequestsCompleted = function()
{
  var i = 0;
  while ( request = this.requests[i++] )
  {
    if ( request.completed === false )
    {
      return false;
    }
  }
  return true;
},

ParallelAjaxExecuter.prototype.checkAndComplete = function()
{
  if ( this.allRequestsCompleted() )
  {
    this.onComplete( this.results );
  }
}

var pe = new ParallelAjaxExecuter( function( results )
{
  alert( eval( results.join( '+' ) ) );
} );

pe.addRequest( $.get, 'test.php', {n:1}, 'text' );
pe.addRequest( $.get, 'test.php', {n:2}, 'text' );
pe.addRequest( $.get, 'test.php', {n:3}, 'text' );
pe.addRequest( $.get, 'test.php', {n:4}, 'text' );

pe.dispatchAll();

</script>

这是 test.php

<?php

echo pow( $_GET['n'], 2 );

?>

更新:根据 Yair Leviel 给出的答案,此答案已过时。使用Promise库,如 jQuery.when() 或 Q.js。


我创建了一个通用解决方案作为 jQuery 扩展。可以使用一些微调使其更通用,但它适合我的需求。在撰写本文时,该技术相对于本文中其他技术的优势在于可以使用任何类型的带有回调的异步处理。

注意:如果我认为我的客户可以依赖另一个第三方库,我会使用 JavaScript 的 Rx 扩展而不是这个 :)

// jQuery extension for running multiple async methods in parallel
// and getting a callback with all results when all of them have completed.
//
// Each worker is a function that takes a callback as its only argument, and
// fires up an async process that calls this callback with its result.
//
// Example:
//      $.parallel(
//          function (callback) { $.get("form.htm", {}, callback, "html"); },
//          function (callback) { $.post("data.aspx", {}, callback, "json"); },
//          function (formHtml, dataJson) { 
//              // Handle success; each argument to this function is 
//              // the result of correlating ajax call above.
//          }
//      );

(function ($) {

    $.parallel = function (anyNumberOfWorkers, allDoneCallback) {

    var workers = [];
    var workersCompleteCallback = null;

    // To support any number of workers, use "arguments" variable to
    // access function arguments rather than the names above.
    var lastArgIndex = arguments.length - 1;
    $.each(arguments, function (index) {
        if (index == lastArgIndex) {
            workersCompleteCallback = this;
        } else {
            workers.push({ fn: this, done: false, result: null });
        }
    });

    // Short circuit this edge case
    if (workers.length == 0) {
        workersCompleteCallback();
        return;
    }

    // Fire off each worker process, asking it to report back to onWorkerDone.
    $.each(workers, function (workerIndex) {
        var worker = this;
        var callback = function () { onWorkerDone(worker, arguments); };
        worker.fn(callback);
    });

    // Store results and update status as each item completes.
    // The [0] on workerResultS below assumes the client only needs the first parameter
    // passed into the return callback. This simplifies the handling in allDoneCallback,
    // but may need to be removed if you need access to all parameters of the result.
    // For example, $.post calls back with success(data, textStatus, XMLHttpRequest).  If
    // you need textStatus or XMLHttpRequest then pull off the [0] below.
    function onWorkerDone(worker, workerResult) {
        worker.done = true;
        worker.result = workerResult[0]; // this is the [0] ref'd above.
        var allResults = [];
        for (var i = 0; i < workers.length; i++) {
            if (!workers[i].done) return;
            else allResults.push(workers[i].result);
        }
        workersCompleteCallback.apply(this, allResults);
    }
};

})(jQuery);
我已经使用过这个,而且效果很好!...但我确实有一个改进:如果您修改最终回调调用以使用“apply”,那么您将获得单独的回调参数而不是单个参数列表:即workersCompleteCallback.apply(this,allResults);
2021-03-28 16:12:23