The premise of knowledge
-
After parsing the HTML, you will get a DOM tree and a CSS tree, and then perform layout and paint according to these two trees. (The exact rendering process will be covered in another article.)
-
A complete render of the renderer process is shown below :(actually including multiple threads)
-
It is easy to think of the rendering process as having three main threads: the main thread (mainly used for rendering), the JS engine thread, and the IO thread.
-
The main thread will not render while JS is being evaluated, because it may need to be re-rendered during js execution. (Of course, this can lead to page stalling when js tasks take a long time.)
-
When the IO thread listens for a callback to fire (such as a button click event), it places the callback in the macro queue of the event loop.
-
When the JS execution stack in the JS engine is empty, a macro task is executed first, and then the micro task is emptied. And it doesn’t have to trigger a render after each event loop; (The specific event cycle will be introduced in another article)
A layout is triggered in the click event
Example code is as follows:
<label id="label" style="font-size: "></label> < button@click ="addCount">click</button> const handleAdd = () => {// render 0 let label = document.getElementById('label') if (label) { label.innerHTML = '0' } }Copy the code
When the button is clicked, the callback will be pushed into the JS execution stack. After the JS execution, the DOM element layout changes, resulting in layout and paint.
The browser records are as follows:
Paint was triggered in the click event
Example code is as follows:
<label id="label" style="font-size: 34px">0</label> < button@click ="addCount">click</button> const handleAdd = () => {// let label = document.getElementById('label') if (label) { label.style.color = 'red' } }Copy the code
When the button is clicked, the callback that is clicked first is pushed into the js stack. Then, after the JS execution, the layout of the DOM element has not changed, but the color has changed, so we need to paint.
The browser records are as follows:
Click the event to synchronize the DOM that has been modified 100 times
Example code is as follows:
<label id="label" style="font-size: </label> < button@click ="addCount">click</button> const handleAdd = () => { i<100; i++) { let label = document.getElementById('label') if (label) { label.innerHTML = `${i}` } } }Copy the code
As a result, the number 99 appears on the page;
When the button is clicked, the callback that is clicked first is pushed into the JS execution stack. The 100 changes in the callback are executed in a macro task. When the JS execution is complete, layout and Paint are triggered. (Note that 100 renders are not triggered)
The browser records are as follows:
10 asynchronous modifications were triggered in the click event
For screenshots, I changed the DOM 10 times, but all in the setTimeout callback;
Example code is as follows:
<label id="label" style="font-size: </label> < button@click ="addCount">click</button> const handleAdd = () => { Dom let a =0 let label = document.getElementById('label') for (let I =0; i<10; i++) { setTimeout(()=>{ if (label) { a++ label.innerHTML = `${a}` } }, 100) } }Copy the code
When the button is clicked, the callback that is clicked first is pushed onto the JS execution stack. In the callback, we create 10 macro tasks in which we modify dom elements. It was expected that layout and Paint would be triggered once at the end of each macro task, resulting in 10 renderings. But the browser obviously doesn’t do that. After the macro task is done, the browser decides whether to render or not; Therefore, each round of event loop does not necessarily correspond to a browser rendering, but depends on the screen refresh frequency and page performance.
The browser records are as follows:
summary
- The callback of the click event is placed in the macro task, and then pushed into the JS execution stack. After execution, if the DOM element is modified, a rendering will be triggered.
- When there are multiple macro tasks that trigger consecutively, not every macro task will trigger a render at the end of each macro task. It is likely that a render will be triggered after several macro tasks are executed.