Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

async update DOM from Promises

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.

like image 371
Nicolas Avatar asked Sep 03 '15 15:09

Nicolas


1 Answers

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.

like image 172
marekful Avatar answered Sep 28 '22 06:09

marekful