Получение суммы от нескольких запросов AJAX - PullRequest
1 голос
/ 25 августа 2011

Я пытаюсь получить общее количество от возврата нескольких запросов ajax, сейчас я использую синхронизацию, чтобы заставить ее работать, так как я думаю, что это было бы намного лучшим решением.

Вот мой кофе

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 ]

4 голосов
/ 25 августа 2011

Я не знаю CoffeeScript, поэтому вот чистое решение jQuery:

Вы не можете вернуть значение из get_total без выполнения синхронных вызовов. Что вы можете сделать, это вызвать обратный вызов после завершения всех запросов.

В этом примере используются объекты Deferred jQuery [документы] :

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, чтобы вернуть значение, то вы должны сделать синхронные вызовы. В общем, это плохая идея, особенно когда вы делаете несколько запросов. Это заморозит пользовательский интерфейс браузера. Лучше реструктурировать код для работы с обратными вызовами.

Обновление: Я только что прочитал последнее предложение вашего вопроса. Вы можете передать динамическое число аргументов функции, используя .apply() [MDN] .

Update2: Конечно, если у вас есть контроль над сервисом, вы должны заставить его принимать несколько ключевых слов, чтобы избежать нескольких запросов Ajax.

1 голос
/ 25 августа 2011

Я не знаю 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 раз.


РЕДАКТИРОВАТЬ: Как указал Феликс, оригинальная версия не поддерживала ожидание, пока вызовы Ajax не были сделаны. Код был обновлен для поддержки отсрочки итога. Это должно сработать, но ответ Феликса, вероятно, немного чище в этот момент.

1 голос
/ 25 августа 2011

Конечно, но вам нужно добавить некоторое отслеживание состояния, чтобы выяснить, когда все запросы ajax вернулись, затем вызвать функцию для передачи сгенерированного итога. Если вы переключитесь на асинхронные запросы, то «total» будет возвращено сразу после того, как ajax-запросы будут запущены, к этому времени может быть только 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
          }
      }
   });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...