Javascript/JQuery中的异步映射/减少

Asynchronous map/reduce in Javascript/JQuery

本文关键字:映射 减少 异步 JQuery Javascript      更新时间:2024-01-10

在Javascript(jQuery)中执行以下操作的惯用方法是什么?

  • 生成一组异步作业
  • 收集部分结果
  • 每个作业完成后,合并部分结果

以上可以通过以下方式实现(为了简单起见,假设按顺序处理请求;在更现实的情况下,计数器可以完成这项工作):

var results = new Array();
$.each(objs, function(i,obj)){
  $.getJSON(make_async_request(obj), function(data) {
    results[data.key] = data.value;
    if (i == objs.length-1)
      elaborate(results);
  }
});

这在我看来很难看。有什么建议吗?

您可以这样使用jQuery.Deferred

   $.when($.get('/a/'), $.get('/b/')).then(function() {
       // all gets are ready
   });

如果需要将所有结果合并到一个对象中,可以循环then回调中的参数:

$.when($.get('/a/'), $.get('/b/')).then(function() {
    var results = {},
        args = Array.prototype.slice.call(arguments),
        data;
    $.each( args, function(i, resp) {
        data = resp[0];  // resp is the results array
        results[data.key] = data.value;
    });
    console.log(results);
});
var results = [], ajaxes = [];
$.each(objs, function(i,obj)){
    var xhr = $.ajax({
        url: make_async_request(obj),
        dataType: 'json'
    }).done(function() {
        results[data.key] = data.value;
        if (i == objs.length-1) elaborate(results);
    });
    ajaxes.push(xhr);
});
$.when.apply(null, ajaxes).done(function() {
    alert('all ajaxes are done');
});

由于$.getJSON是异步的,并且在发出请求后立即返回,因此在发出最后一个请求后,您的检查结果将为true。

通过利用$.ajax$.getJSON返回Deferred这一事实,您可以有效地执行您想要的操作。使用$.when$.map收集所有请求的数据进行处理。看看jQuery中的延迟/承诺api,它们非常强大,允许以下一行代码工作:

$.when($(objs).each(function (i, obj) { return $.getJSON(make_async_request(obj)); }), elaborate);

完全公开:公然插入我自己的库,队列流:)

q(objs)
    .map(q.async(function(obj, callback) {
        $.getJSON(make_async_request(obj), callback);
    }))
    .reduce(function(results, data) {
        results[data.key] = data.val;
        return results;
    }, elaborate, {});

队列流使用队列的概念使异步功能代码看起来几乎完全同步。:)它还可以让你用源代码组织做一些非常有趣的事情,看看GitHub上readme中的.branch方法。(刚刚更新了我的示例,以匹配问题示例中的更改。)

也可以写成:

q(objs)
    .map(make_async_request)
    .map(q.async($.getJSON))
    .reduce(function(results, data) {
        results[data.key] = data.val;
        return results;
    }, elaborate, {});

这真的很酷,但对于不熟悉的人来说可能需要一点时间才能摸索。:)

截至2018年的更新:现在你可以使用了

results = await Promise.all(objs.map(someAsyncFunction));

其中CCD_ 9应该是某个列表,而CCD_。有关更多详细信息,请参阅此问题的答案:在map中调用异步函数的最佳方式?