async update DOM from Promises
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.
Nicolas
Updated on June 27, 2022Comments
-
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 over 8 yearsWhy bother even keeping the promise stuff? It isn't helping at all.
-
jib over 8 yearsJS 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 usingsetTimeout
. Instead, consider a helper-function like:var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
-
Nicolas over 8 yearsYes 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.