2017-01-11 2 views
2

Я загружаю коллекцию блоков данных с помощью AJAX. Каждый из этих блоков должен быть визуализирован в DOM по порядку, поэтому я запрашиваю первый блок и его рендеринг, затем запрашиваю следующее и так далее до последнего. Когда последний сделано, отложенный объект разрешен сигнализировать другую функцию были загружены все блоки:Множественный успех AJAX на заказ

function loadBlock(block, limit) { 
    var deferred = $.Deferred(); 
    (function request(block, limit) { 
    $.ajax({ 
     url: 'block/' + block, 
     success: function(html) { 
     $('#block-' + block).html(html); 
     var nextBlock = block + 1; 
     if (nextBlock <= limit) 
      request(nextBlock, limit); 
     else 
      deferred.resolve(); 
     } 
    }); 
    })(block, limit); 

    return deferred.promise(); 
} 

Однако все это ожидание предыдущего запроса будет завершено может замедлить этот процесс много.

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

Пример: отправлено 10 запросов. Мы хотели бы сделать блоки по порядку: 1, 2, 3, ... Предположим, что запросы для первых трех блоков завершены в порядке, поэтому блоки загружаются на страницу по мере необходимости, но затем блок 5 готово перед блоком 4, мы хотели бы оставить блок 5 где-то и показать его на странице только после того, как будет сделан блок 4, то есть после выполнения запроса для блока 4 и его визуализации.

Мои вопросы, то есть:

  • Как я могу запустить параллельно несколько функций, стреляющие запросы и другие функции, погрузочные блок на странице?
  • Как я могу сигнализировать функции загрузки определенного блока, который был сделан предыдущим, чтобы он мог продолжить?

Кроме того, мне нужно будет оставить отложенную логику, потому что мне все еще нужно сигнализировать о завершении всего процесса.

ответ

1

Самый элегантный способ сделать это состоит в использовании Promise.all()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

более элементарным способом было бы пометить int для хранения выполненных запросов или массив Booleans, который проверяется после каждого AJAX запрос завершен.

+0

Можете ли вы разработать свой ответ немного больше? Я не вижу, как интегрировать это в моем сценарии. – dabadaba

0

Вы можете сделать это следующим образом:

var loadBlockOneDef = loadBlock(block, limit); 
var loadBlockTwoDef = loadBlock(block, limit); 
... 
Promise.all([loadBlockOneDef, loadBlockTwoDef, ..]) 
    .then(function (values){ 
     //DO STUFF 
    } 

Параметр для Promise.all() представляет собой массив обещаний/deferreds. Значения представляют собой массив каждого обещания в массиве, значения [0] -> разрешение-значение loadBlockOneDef, ...

+0

Как я понимаю, OP не хочет ждать, пока все не будет завершено, единственным ограничением является то, что полезная нагрузка должна быть указана в правильном порядке. –

0

Это гарантирует немедленное выполнение запроса ajax, но разрешается в порядке. Он всегда ждет, пока предыдущий Deferred будет разрешен, до , разрешив текущий (даже если текущий ajax-вызов завершен до предыдущего).

var loadBlock = (function(previous){ 
    //the purpose of `removePreviousResponse` is to clean up 
    //the arguments returned by the Deferred 
    //and to stay consistent with the behaviour of $.ajax() 
    function cleanupArguments(previousArgs, currentArgs){ 
     //here `$.when()` is resolved with two arguments, 
     //the args for the previous and for the current ajax call 
     //we want only the args for the current ajax-call to be further propagated 

     //since we can not return multiple values, we wrap them into a Deferred 
     //that is resolved with multiple arguments 
     var deferred = $.Deferred(); 
     deferred.resolve.apply(deferred, currentArgs); 
     return deferred.promise(); 
    } 

    return function(block){ 
     //resolves when _both_ promises are done, 
     //the previous one and the current 
     var current = $.when(previous, $.get('block/' + block)) 
      .then(cleanupArguments) 
      .done(function(html, success, evt){ 
       //add html to the DOM 
       $('#block-' + block).html(html); 
      }); 

     previous = current; 
     return current; 
    } 
})(null); 

//the blocks are added in that order that you call `loadBlock()` 
loadBlock(0); 
loadBlock(1); 
loadBlock(3).then(function(html, success, evt){ 
    //you can even append further logic 
    console.log("block 3 has been loaded"); 
}); 
loadBlock(2); 
+0

вы можете более подробно объяснить, как это делается? Кроме того, я не понимаю первый комментарий. Кроме того, как хранится там отложенный объект? – dabadaba

+0

@dabadaba, я отредактировал ответ, может быть, теперь это более ясно.Я предполагаю, что вы имеете в виду, как хранится «предыдущая» отсрочка? он хранится в переменной 'previous' и обновляется каждым вызовом' loadBlock() ', чтобы всегда содержать последнюю отложенную. Я также немного изменил логику в функции очистки, чтобы получить более последовательный результат. – Thomas

Смежные вопросы