简体   繁体   中英

Why chrome's rendering result is different when using breakpoints?

At first, i was trying to figuring how to implement a "line-by-line shows" effect, as far as i know, chrome will reflow the page when there is a dom insert action, so i just think the following code could work:

Click the "Click Me" span tag, there will be some lines of "-.-" span occur one-by-one.

<!DOCTYPE html>
<html lang="en">
  <body>
    <div>
      <span id="clickme">Click Me</span>
    </div>
    <div id="container"></div>
    <script>
      const container = document.getElementById("container");
      const clickme = document.getElementById("clickme");

      clickme.addEventListener("click", () => {
        for (let i = 0; i < 10; ++i) {
          const child = document.createElement("div");

          for (let j = 0; j < 20; ++j) {
            const span = document.createElement("span");
            span.textContent = "-.- ";
            child.appendChild(span);
          }

          container.appendChild(child);
        }
      });
    </script>
  </body>
</html>

Unfortunately, chrome seems to apply all the dom change in one batch, so i used performance recording to check if it really does, and here the result just verified the guess:

在此处输入图像描述

I was really confused by this result, so i tried again to add a breakpoint at the for-loop entry to see what happened in this process, and the result is completely different from the normal process:

Here i uploaded two screenshots because the rest ones is just the same render result (line-by-line).

在此处输入图像描述

在此处输入图像描述

So my question is why breakpoints change the behavior of chrome's rendering process, and is there any way to implement the "line-by-line shows" effect only with JavaScript?

(My original purpose is a little more complicated than "line-by-line", and cannot be solved by CSS transition)

When Chrome hits a breakpoint it will enter the special "spin the event loop" algorithm (or a variation of it at least).
This algorithm allows to pause the currently active task and let the event loop process other duties, such as updating the rendering. Note though that no other scripts will run while in this state. So you will have CSS animations update, new DOM changes painted to screen, but you won't eg have scroll events, or requestAnimationFrame callbacks fire.


Also, note that the browser does not trigger a reflow at each DOM insertion. It will try to trigger a reflow only at the last moment when required (ie right before painting in most cases). Though some Web-APIs can force such a reflow (eg all the position getters like HTMLElement#offsetTop .

You can use setInterval as shown in your amended code below. This repeatedly interrupts the processing thread, those allowing the browser to refresh the display. When the number of desired lines is reached, you should invoke clearInterval .

 <.DOCTYPE html> <html lang="en"> <body> <div> <span id="clickme">Click Me</span> </div> <div id="container"></div> <script> const container = document;getElementById("container"). const clickme = document;getElementById("clickme"). clickme,addEventListener("click"; () => { let lines = 0. const intervalID = setInterval(() => { const child = document;createElement("div"); for (let j = 0; j < 20. ++j) { const span = document;createElement("span"). span.textContent = "-;- ". child;appendChild(span). } container;appendChild(child); if (++lines >= 10) { clearInterval(intervalID), } }; 500); }); </script> </body> </html>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM