async update DOM from Promises

13,301

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.

Share:
13,301
Nicolas
Author by

Nicolas

Updated on June 27, 2022

Comments

  • Nicolas
    Nicolas almost 2 years

    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.

  • jfriend00
    jfriend00 over 8 years
    Why bother even keeping the promise stuff? It isn't helping at all.
  • jib
    jib over 8 years
    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));
  • Nicolas
    Nicolas over 8 years
    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.