从多个ajax请求中获取总数

时间:2011-08-25 15:46:47

标签: jquery ajax asynchronous

我想从多个ajax请求的返回中得到一个总数,我现在使用sync来使其工作,因为我认为这将是一个更好的解决方案。

这是我的咖啡

get_total = (trend, duration) ->
  total = 0
  for keyword in trend.search_terms
    url = "http://otter.topsy.com/search.json?q=#{keyword}&window=#{duration}"
    $.ajax
      url: url
      async: false
      success: (data) ->
        total += data.response.total
  total

很好地编译

  get_total = function(trend, duration) {
    var keyword, total, url, _i, _len, _ref;
    total = 0;
    _ref = trend.search_terms;
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      keyword = _ref[_i];
      url = "http://otter.topsy.com/search.json?q=" + keyword + "&window=" + duration;
      $.ajax({
        url: url,
        async: false,
        success: function(data) {
          return total += data.response.total;
        }
      });
    }
    return total;
  };

有没有办法在不使用同步js的情况下完成总工作。

我一直在试验$ .when()。then()但是当请求的大小是动态的时候会导致问题。

3 个答案:

答案 0 :(得分:4)

我不知道CoffeeScript,所以这里是一个纯粹的jQuery解决方案:

在不进行同步调用的情况下,您无法get_total返回值。所有请求完成后,您可以做的是调用回调。

此示例使用jQuery的Deferred objects [docs]

function get_total(trend, duration, callback) {
    var deferreds = [], total = 0;

    for(var i = 0, l = trend.search_terms.length; i < l; i++) {
        deferreds.push($.get("http://otter.topsy.com/search.json?q=" + trend.search_terms[i] + "&window=" + duration, function(data) {
            total += data.response.total;
        }));
    }

    $.when.apply($, deferreds).then(function() {
        callback(total);
    });
}

用法:

get_total(trend, 200, function(total) {
   // now execute the code that needs `total`
});

如果您需要get_total来返回值,则必须进行同步调用。一般来说,这是一个坏主意,尤其是在您提出多个请求时。它将冻结浏览器的UI。最好重构代码以使用回调。

更新:我刚看完你问题的最后一句话。您可以使用.apply() [MDN]将动态数量的参数传递给函数。

Update2:当然,如果您可以控制该服务,则应该接受多个关键字以避免多个Ajax请求。

答案 1 :(得分:1)

当然,但您需要添加一些状态跟踪来确定所有ajax请求何时返回,然后调用函数来传递生成的总数。如果您切换到异步请求,那么在触发ajax请求后会立即返回'total',此时可能只返回0或几个请求,因此您将获得不正确的总数。

var requestsOutstanding = 0;
var total = 0;
for (i = 0; i < _ref.length) {
   keyword = _ref[i];
   url = "...";
   requestsOutstanding++;
   $.ajax({
      url: url,
      async: true,
      success: function(data) {
          total += data.response.total;
          requestsOutstanding--;
          if (requestsOutstanding == 0) {
             totalResultIsAvailable(total); // trigger next stage of events here
          }
      }
   });
}

答案 2 :(得分:1)

我不知道coffeescript,但要在js中执行此操作,您可以使用闭包:

var total_trend = (function() {
    var total = 0,
        num_adds = 0;

    return {
        add_to_total: function(add) { total += parseInt(add, 10); num_adds += 1; },
        get_total: function() { return total; },
        get_deferred_total: function(expected, callback) {
            if(num_adds !== expected) {
                var _this = this;
                setTimeout(function(){ return _this.get_deferred_total(expected, callback); }, 100);
            } else {
                callback(total);
            }
        }
    };
})();

将此定义为您的回调可以访问的变量,然后在ajax回调中执行:

total_trend.add_to_total(data.response.total);

当你想要总数时:

total_trend.get_total();

如果你想推迟总数,直到add_to_total有一定数量的电话:

var expected_num_calls = 5;
total_trend.get_deferred_total(expected_num_calls, function(total) { alert(total); } )

在上面的例子中,当调用add_to_total 5次时,将调用回调函数。


编辑:正如Felix所指出的那样,原始版本不支持等待ajax调用完成。代码已更新,以支持推迟总数。这应该有用,但菲利克斯的答案在这一点上可能有点清晰。