5

I want to update the DOM through my promises. I build an array of promises and run them with 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

I can not get the DOM to be updated in real time. It only updates the DOM when all my promises have resolved.

Is it the expected behavior? If so, how can I make use of Promise.all to update my DOM in real time?

I want to use promises instead of the "setTimeout(function, 1000)" hack but I can not find the good way to do it.

Nicolas
  • 1,913
  • 2
  • 22
  • 40
  • I don't see what you consider to be "real time"? – Bergi Sep 03 '15 at 16:27
  • Promises are not "run" by `Promise.all`, they are only awaited - they are already running since you created them. – Bergi Sep 03 '15 at 16:29
  • `Promise.all` waits on an array of promises from asynchronous functions typically launched *in parallel*, not in sequence. – jib Sep 03 '15 at 21:07

1 Answers1

11

In a browser, the DOM queues changes and if they happen in great succession without the main event queue having some "free ticks" like in your case with the for loop, they will be applied at once when the JS manipulating the DOM is finished. See: https://stackoverflow.com/a/31229816/1207049

To overcome this in a browser environment, you can use setTimeout to to push code execution blocks to a different queue:

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

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

    return i;
  });
}

Without the setTimeout each instruction to update the innerHTML of the element is pushed to the end of the same queue. With setTimeout, it's always getting into a new, empty queue and may be executed before items in the main queue.

marekful
  • 13,318
  • 5
  • 30
  • 52
  • 1
    Why bother even keeping the promise stuff? It isn't helping at all. – jfriend00 Sep 03 '15 at 16:08
  • 4
    JS is single-threaded so it's not right to say that `setTimeout` will "detach from the main execution thread". Promises execute on a higher-priority microtask queue, separate from the main event queue, and typically empties at the tail of the current run-to-completion task on the main event queue, I think you mean to say. `Promise.resolve()` is redundant when using `setTimeout`. Instead, consider a helper-function like: `var wait = ms => new Promise(resolve => setTimeout(resolve, ms));` – jib Sep 03 '15 at 21:02
  • Yes I ended up using set timeout to call recursively a function. When I get to the state I want in one of my recursive callback, I resolve the promise. – Nicolas Sep 11 '15 at 10:04