4

I'm having some trouble testing the performance of some code that heavily update the DOM.

To illustrate, i created a simple demo:

function insertListItem() {
  let ul = document.querySelector('ul')
  let start = new Date()
  
  // heavy dom operations
  for (let i = 0; i < N; i++) {
    let li = document.createElement('li')
    li.textContent = 'item' + i
    ul.appendChild(li)
  }
  
  // log the duration (deferred by 0ms timer)
  setTimeout(() => {
    let t2 = new Date() - start
    console.log(`t2: ${t2} ms`)
  }, 0)
 
  // log the duration instantly
  let t1 = new Date() - start
  console.log(`t1: ${t1} ms`)
}

let N = 100000
let btn = document.querySelector('button')
btn.addEventListener('click', insertListItem)
<section>
    <button>insert list item</button>
    <ul></ul>
</section>

The console output of t1, t2 has a HUGE difference which is out of my expectation, the code above besides the timer are all synchronous. Because of the event loop the timer's callback would be pushed into the callback/event queue and waits for execution, this will surely results some extent of delay between t1 and t2 otherwise they're supposed to be roughly the same.

However, t1 behaves as if it's called before the rendering task while t2 is called after the rendering task as expected. What's the reason? How can i change the test for proper measurement?

Allen
  • 4,431
  • 2
  • 27
  • 39
  • 2
    While the t1 is going through before the rendering ```setTimeout({}, 0)``` acts like a 'do after rendering'. I think you can find a better explanation here http://stackoverflow.com/a/779785/763909 – newpatriks Feb 25 '17 at 17:54
  • So, what values are you getting for various Ns? What was you expectation, and what is the huge difference? What browser/engine (version) did you run this in? – Bergi Feb 25 '17 at 18:04
  • @newpatriks exactly as you say, `t1` behaves as 'log before rendering' while `t2` as 'log after rendering'. I'm confused that the web DOM api are all synchronous apis, why `t1` can be called before the rendering task is done? – Allen Feb 25 '17 at 18:22
  • @Bergi values are as @newpatricks says. I expect `t1` to act as 'log after the rendering task is done'. I'm currently on latest Chrome. My guess is that it has something to do with the browser runtime instead of the JS thread only, but i'm a bit lost here. – Allen Feb 25 '17 at 18:26
  • @Bergi For e.g N=100000, t1= 200ms,t2=7000ms; I expect t1=t2=7000ms. – Allen Feb 25 '17 at 18:43
  • No, `t1` will be the time it needs to insert everything in the DOM (which is pretty fast), rendering happens asynchronously - all at once, when you're done with the updates, not on every single `appendChild` call. – Bergi Feb 25 '17 at 19:46
  • @Bergi If a) the insertion of DOM is *pretty fast* and b) rendering processing runs async, how does it explain the `block of UI` when you run the test above, what's JS execution stack running? – Allen Feb 25 '17 at 19:58
  • The UI does freeze? Probably because you've got too many DOM nodes and rendering is slow… Afaik JS execution is stopped during reflow computations so that those don't interfere (usually they're just interleaved so that you don't notice a thing) – Bergi Feb 25 '17 at 23:00

0 Answers0