1

What's the idiomatic way to do the following in Javascript (jQuery)?

  • Spawn a set of asynchronous jobs
  • Collect partial results
  • When every job has completed, combine partial results

The above can be achieved by something on the lines of (assuming for simplicity that requests are processed in order; in a more realistic case, a counter would do the job):

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

Which looks ugly to me. Any suggestions?

4

5 回答 5

1

你可以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);
});
于 2012-07-22T16:03:37.933 回答
0

您检查作业的完成情况是不充分的,因为$.getJSON异步并在发出请求后立即返回,因此一旦发出最后一个请求,您的检查将评估为真。

$.ajax您可以通过利用事实并因此$.getJSON返回Deferreds来有效地做您想做的事情。使用$.when$.map收集所有处理请求的数据。看看 jQuery 中的 deferred/promise api,它们非常强大,并且允许像下面这样的单线工作:

$.when($(objs).each(function (i, obj) { return $.getJSON(make_async_request(obj)); }), elaborate);
于 2012-07-22T16:20:40.047 回答
0
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');
});
于 2012-07-22T16:14:55.487 回答
0

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

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, {});

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

这也可以写成:

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

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

于 2012-07-22T21:52:58.463 回答
0

2018 年更新:现在您可以使用

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

whereobjs应该是一些列表并someAsyncFunction获取该列表的一个元素并返回一个带有结果的承诺。有关更多详细信息,请参阅此问题的答案:Best way to call an async function within map?

于 2021-04-25T12:46:41.753 回答