Постановка в очередь/дросселирование запросов jQuery ajax

Мне нужно запустить несколько запросов ajax на сервер, а затем запустить обратный вызов, когда они будут завершены. Обычно это было бы легко сделать с помощью jQuery deferred.done() . Однако, чтобы не перегружать сервер, я ставлю запросы в очередь и запускаю их каждые X миллисекунд.

e.g

var promisesList = [];

var addToQueue = function(workflow) {
    workflowQueue.push(workflow);
  }

var startWorkflow = function(workflow) {
    return $.ajax($endointURL, {
      type: "POST",
      data: {
        action: workflow.id
      },
      success: function() {
      },
      error: function(jqXHR, textStatus, errorThrown) {
      }
    });
  };

  var startWorkflows = function() {
    var promisesList = [];
    if (workflowQueue.length > 0) {
      var workflow = workflowQueue.shift();
      promisesList.push(startWorkflow(workflow));
      setTimeout(startWorkflows, delay);
    }
  };

startWorkflows();
$.when(promisesList).done(function(){
  //do stuff
});

Проблема в том, что массив promisesList изначально пуст, поэтому обратный вызов done() срабатывает немедленно, а затем запросы ajax начинают отправляться массивом setTimeout(). Есть ли простой способ сначала создать запросы ajax и как бы «приостановить» их, а затем запустить их с помощью setTimeout().

Я нашел различные реализации дросселя/очереди для последовательного запуска ajax-запросов, но я рад, что они выполняются параллельно, просто с задержкой.


person Mark    schedule 04.07.2014    source источник
comment
setTimeout с произвольной задержкой не вариант?   -  person SpaceBison    schedule 04.07.2014
comment
Я использую setTimout(), проблема заключается в обработке объектов deferred.   -  person Mark    schedule 04.07.2014
comment
Я предполагаю, что вам нужно обрабатывать часть $.when для каждого запроса... или что вы ждете, пока все не будет отправлено, а затем делаете, когда...   -  person mmm    schedule 04.07.2014


Ответы (1)


Первое, на что вы натыкаетесь, это то, что when() не работает таким образом с массивами. Он принимает произвольный список промисов, поэтому вы можете обойти это, применив массив, используя:

$.when.apply(null, promiseList).done(function(){
    // Do something
    // use the `arguments` magic property to get an ordered list of results
});

Во-вторых, метод дросселирования может быть выполнен с параметром $.ajax {delay:timeInSeconds}, но я предложил решение, которое устанавливает новый отложенный, который немедленно возвращается (для сохранения порядка), но разрешается после тайм-аута.

См. интерактивный пример на http://jsfiddle.net/9Acb2/1/.

person James Broad    schedule 04.07.2014
comment
(а) Я был уверен, что $.when() работает именно так! Проверено, и вы правы, он не принимает массивы. Странно, это кажется очевидным. (b) Я не вижу параметр delay в документах jQ для запросов ajax? (c) Ваша скрипка идеальна, я не думал вручную создавать $.Deferreds() вот так. Большое спасибо! - person Mark; 04.07.2014