асинхронное обновление DOM из Promises

Я хочу обновить DOM через свои обещания. Я создаю массив промисов и запускаю их с помощью Promise.all:

function test(i){
  return Promise.resolve()
  .then(function() {
    // update the DOM
    document.getElementById('progress').innerHTML += i;
    return i;
  });
}

var loadSequence = [];
// loop through all the frames!
for (var i = 0; i < 9999; i++) {
  loadSequence.push(test(i));
}

Promise.all(loadSequence)
.then(function(){
  window.console.log('all set...');
});

http://codepen.io/nicolasrannou/pen/jbEVwr

Я не могу заставить DOM обновляться в режиме реального времени. Он обновляет DOM только тогда, когда все мои обещания выполнены.

Это ожидаемое поведение? Если да, то как я могу использовать Promise.all для обновления своего DOM в режиме реального времени?

Я хочу использовать промисы вместо взлома "setTimeout (функция, 1000)", но я не могу найти хороший способ сделать это.


person Nicolas    schedule 03.09.2015    source источник
comment
Я не понимаю, что вы считаете реальным временем?   -  person Bergi    schedule 03.09.2015
comment
Промисы не выполняются Promise.all, они только ожидаются — они уже выполняются с тех пор, как вы их создали.   -  person Bergi    schedule 03.09.2015
comment
Promise.all ожидает массив промисов от асинхронных функций, которые обычно запускаются параллельно, а не последовательно.   -  person jib    schedule 04.09.2015


Ответы (1)


В браузере очереди DOM изменяются, и если они происходят в большой последовательности без основной очереди событий, имеющей несколько «свободных тиков», как в вашем случае с циклом for, они будут применены сразу, когда JS, манипулирующий DOM, будет завершен. См.: https://stackoverflow.com/a/31229816/1207049

Чтобы преодолеть это в среде браузера, вы можете использовать setTimeout для отправки блоков выполнения кода в другую очередь:

function test(i){
  return Promise.resolve()
  .then(function() {

    // update the DOM
    setTimeout(function() {
      document.getElementById('progress').innerHTML += i;
    }, 0);

    return i;
  });
}

Без setTimeout каждая инструкция по обновлению innerHTML элемента помещается в конец той же очереди. С setTimeout он всегда попадает в новую пустую очередь и может выполняться перед элементами в основной очереди.

person marekful    schedule 03.09.2015
comment
Зачем вообще выполнять обещания? Это совсем не помогает. - person jfriend00; 03.09.2015
comment
JS является однопоточным, поэтому нельзя говорить, что setTimeout отсоединится от основного потока выполнения. Промисы выполняются в очереди микрозадач с более высоким приоритетом, отдельно от основной очереди событий, и обычно опустошаются в хвосте текущей задачи выполнения до завершения в основной очереди событий, я думаю, вы хотите сказать. Promise.resolve() является избыточным при использовании setTimeout. Вместо этого рассмотрите вспомогательную функцию, например: var wait = ms => new Promise(resolve => setTimeout(resolve, ms)); - person jib; 04.09.2015
comment
Да, в итоге я использовал set timeout для рекурсивного вызова функции. Когда я дохожу до состояния, которое хочу, в одном из моих рекурсивных обратных вызовов, я разрешаю обещание. - person Nicolas; 11.09.2015