Ensiklopedia VibeKoding: Principles of Browser Rendering.Ensiklopedia VibeKoding: Principles of Browser Rendering.
Why are some web pages smooth as silk while others stutter like a slideshow? How does the browser turn a pile of HTML, CSS, and JavaScript into the page you see? This chapter takes you inside the browser's "workshop" to understand its workflow so you can write higher-performance web pages.Why are some web pages smooth as silk while others stutter like a slideshow? How does the browser turn a pile of HTML, CSS, and JavaScript into the page you see? This chapter takes you inside the browser's "workshop" to understand its workflow so you can write higher-performance web pages.
What will this article teach you?What will this article teach you?
| Chapter | Content | What You'll Be Able to Do |
|---|---|---|
| Chapter 1 | Why understand the rendering pipeline | Understand the necessity of performance optimization |
| Chapter 2 | The five stages of the rendering pipeline | Master the basic browser rendering process |
| Chapter 3 | Building the DOM tree and CSSOM tree | Understand how HTML and CSS are parsed |
| Chapter 4 | Building the render tree | Know which elements get rendered |
| Chapter 5 | Layout and reflow | Avoid triggering expensive layout calculations |
| Chapter 6 | Paint and repaint | Reduce unnecessary paint operations |
| Chapter 7 | Compositing and GPU acceleration | Leverage GPU to improve animation performance |
| Chapter 8 | Event loop | Understand JavaScript's execution mechanism |
| Chapter 9 | Performance optimization in practice | Master common performance optimization techniques |
Each chapter starts with "understanding the principles" โ you don't need to hand-write optimization code. When you encounter performance issues, come back and reference this anytime.Each chapter starts with "understanding the principles" โ you don't need to hand-write optimization code. When you encounter performance issues, come back and reference this anytime.
------
When you first learn frontend, you only care whether the code "works" โ the page displays, buttons are clickable, and that's success. But as projects grow and users increase, you'll quickly face a harsh reality: for the same functionality, some people's pages are buttery smooth, while others stutter so badly users want to throw their mouse.When you first learn frontend, you only care whether the code "works" โ the page displays, buttons are clickable, and that's success. But as projects grow and users increase, you'll quickly face a harsh reality: for the same functionality, some people's pages are buttery smooth, while others stutter so badly users want to throw their mouse.
It's like learning to drive. Beginners only care about "can the car move," but experienced drivers care about "when to shift gears, when to brake, how to drive most efficiently." The browser is the "car" you're driving โ understanding its "working habits" lets you drive fast and smooth.It's like learning to drive. Beginners only care about "can the car move," but experienced drivers care about "when to shift gears, when to brake, how to drive most efficiently." The browser is the "car" you're driving โ understanding its "working habits" lets you drive fast and smooth.
๐ข Beginner Mindset (Functionality Only)๐ข Beginner Mindset (Functionality Only) Advanced Mindset (Experience Focused) Advanced Mindset (Experience Focused)
Understanding the rendering pipeline is the key step from "it works" to "it's fast."Understanding the rendering pipeline is the key step from "it works" to "it's fast."
Xiao Zhang is a frontend engineer at an e-commerce company, responsible for optimizing the product detail page. The page was horribly laggy when displaying product information, and user complaints kept pouring in. Xiao Zhang thought: "The page is laggy probably because there are too many DOM elements. I'll hide them with display:none first, modify them, then show them again โ that way the browser won't re-render repeatedly, right?" So he wrote this code: ``javascript // The "optimization" you thought you were doing const container = document.getElementById('list') container.style.display = 'none' // Hide first โ shouldn't trigger rendering, right? for (let i = 0; i < 1000; i++) { const item = document.createElement('div') item.style.width = Math.random() * 100 + 'px' // Random width container.appendChild(item) } container.style.display = 'block' // Show at the end, render once ` After testing, the page was even laggier! Xiao Zhang was baffled: he had clearly "optimized" it, so why was it slower? Later, the frontend lead looked at the code and pointed out the problem: although the elements were hidden, each modification to style.width still triggered the browser's style recalculation and layout invalidation. The browser was doing a ton of useless work in the background. The correct approach is to use DocumentFragment` to batch operations in memory, then insert into the DOM once, triggering only a single render.Xiao Zhang is a frontend engineer at an e-commerce company, responsible for optimizing the product detail page. The page was horribly laggy when displaying product information, and user complaints kept pouring in. Xiao Zhang thought: "The page is laggy probably because there are too many DOM elements. I'll hide them with display:none first, modify them, then show them again โ that way the browser won't re-render repeatedly, right?" So he wrote this code: ``javascript // The "optimization" you thought you were doing const container = document.getElementById('list') container.style.display = 'none' // Hide first โ shouldn't trigger rendering, right? for (let i = 0; i < 1000; i++) { const item = document.createElement('div') item.style.width = Math.random() * 100 + 'px' // Random width container.appendChild(item) } container.style.display = 'block' // Show at the end, render once ` After testing, the page was even laggier! Xiao Zhang was baffled: he had clearly "optimized" it, so why was it slower? Later, the frontend lead looked at the code and pointed out the problem: although the elements were hidden, each modification to style.width still triggered the browser's style recalculation and layout invalidation. The browser was doing a ton of useless work in the background. The correct approach is to use DocumentFragment` to batch operations in memory, then insert into the DOM once, triggering only a single render.
Without understanding the browser's workflow, you might "cleverly" write a bunch of "optimization code" that actually makes performance worse. Understanding the rendering pipeline tells you which operations are expensive and which are cheap, so you avoid putting effort in the wrong places.Without understanding the browser's workflow, you might "cleverly" write a bunch of "optimization code" that actually makes performance worse. Understanding the rendering pipeline tells you which operations are expensive and which are cheap, so you avoid putting effort in the wrong places.
------
Rendering, simply put, is the process by which the browser "draws" code into the web page you see. You can think of it like a printing press producing a book: - HTML = the manuscript content (text, images, chapters) - CSS = the typesetting requirements (font size, color, spacing) - JavaScript = dynamic modifications (the author making last-minute edits, adjusting layout) The browser takes these "materials" and passes them through a series of "processes" before finally "printing" the web page you see. This series of processes is the Rendering Pipeline.Rendering, simply put, is the process by which the browser "draws" code into the web page you see. You can think of it like a printing press producing a book: - HTML = the manuscript content (text, images, chapters) - CSS = the typesetting requirements (font size, color, spacing) - JavaScript = dynamic modifications (the author making last-minute edits, adjusting layout) The browser takes these "materials" and passes them through a series of "processes" before finally "printing" the web page you see. This series of processes is the Rendering Pipeline.
To help you understand better, let's use a bakery as an analogy for the browser's rendering process.To help you understand better, let's use a bakery as an analogy for the browser's rendering process.
Imagine you're running a bakery, making various breads for customers every day. The stages involved in this process are strikingly similar to the browser's rendering pipeline:Imagine you're running a bakery, making various breads for customers every day. The stages involved in this process are strikingly similar to the browser's rendering pipeline:
| Stage | ๐ฅ Bakery Analogy | What the Browser Actually Does | Concrete Example |
|---|---|---|---|
| 1. Prepare Ingredients | Organize the ingredient list (flour, eggs, cream...) | Build the DOM tree: Parse HTML into a tree structure | You write , the browser parses it into a divโpโ"Hello" tree |
| 2. Prepare Recipes | Organize recipe cards (ingredient ratios for each bread) | Build the CSSOM tree: Parse CSS into a tree of rules | You write .title { color: red }, the browser records ".title text is red" |
| 3. Make a Plan | Based on ingredients and recipes, decide what breads to make today | Build the render tree: Merge DOM and CSSOM, keeping only visible elements | tags don't display, so they're not in the render tree |
| 4. Arrange Positions | Place breads in the display case, deciding where each one goes | Layout: Calculate the size and position of each element | Figure out "this div is 200px wide, 100px tall, at position (50, 50) on screen" |
| 5. Decorate | Brush egg wash, sprinkle sesame seeds, pipe cream on breads | Paint: "Draw" elements' colors, borders, shadows, etc. onto the screen | Actually draw "red text" onto the screen |
| 6. Assemble | Stack all bread layers together into a beautiful display | Composite: Merge multiple layers into the final image | GPU combines background layer, text layer, and image layer into one complete picture |
Let's interpret this table row by row to understand each stage of the rendering pipeline: Stages 1-2 (Preparation): The browser first "understands" your code. HTML and CSS are parsed separately because they have different responsibilities โ HTML determines "what content exists," CSS determines "how it looks." Stage 3 (Merging): Why "merge"? Because not all HTML elements are displayed (e.g., , ), the browser needs to combine "visible elements" with "their styles" to form a "blueprint." Stages 4-5 (Drawing): Layout is "calculating positions," paint is "applying colors." Layout changes (e.g., changing width) trigger paint, but paint changes (e.g., changing color) don't trigger layout. Stage 6 (Compositing): The "magic" of modern browsers. The traditional approach is "draw everything at once" (CPU, slow), while the modern approach is "layer-based drawing + GPU compositing" (fast). This is why transform animations are smoother than width animations.Let's interpret this table row by row to understand each stage of the rendering pipeline: Stages 1-2 (Preparation): The browser first "understands" your code. HTML and CSS are parsed separately because they have different responsibilities โ HTML determines "what content exists," CSS determines "how it looks." Stage 3 (Merging): Why "merge"? Because not all HTML elements are displayed (e.g., , ), the browser needs to combine "visible elements" with "their styles" to form a "blueprint." Stages 4-5 (Drawing): Layout is "calculating positions," paint is "applying colors." Layout changes (e.g., changing width) trigger paint, but paint changes (e.g., changing color) don't trigger layout. Stage 6 (Compositing): The "magic" of modern browsers. The traditional approach is "draw everything at once" (CPU, slow), while the modern approach is "layer-based drawing + GPU compositing" (fast). This is why transform animations are smoother than width animations.
------
DOM (Document Object Model) is a tree structure that the browser converts the HTML document into, making it easy for JavaScript to manipulate page elements. You can think of it as a family tree: - The top is the "ancestor" ( After the browser receives the HTML, it doesn't display it immediately โ it first needs to "understand" it. This process has three steps:After the browser receives the HTML, it doesn't display it immediately โ it first needs to "understand" it. This process has three steps: Step 1: Lexical Analysis โ Breaking Code Into "Tokens"Step 1: Lexical Analysis โ Breaking Code Into "Tokens" When the browser sees this code, it first "tokenizes":When the browser sees this code, it first "tokenizes": Step 2: Syntactic Analysis โ Assembling "Tokens" Into "Nodes"Step 2: Syntactic Analysis โ Assembling "Tokens" Into "Nodes" The browser assembles these "tokens" into "nodes" according to HTML rules:The browser assembles these "tokens" into "nodes" according to HTML rules: Step 3: Building the Tree โ Establishing "Parent-Child Relationships"Step 3: Building the Tree โ Establishing "Parent-Child Relationships" Finally, the browser builds a tree structure based on tag nesting:Finally, the browser builds a tree structure based on tag nesting: CSSOM (CSS Object Model) is a tree structure that the browser converts CSS rules into, used to calculate the final style of each element. You can think of it as a wardrobe styling guide: - Upper-level rules (body font) affect lower levels (all child elements) - If there are conflicts (e.g., multiple rules specify different colors for the same element), they're resolved by "specificity" - Ultimately, it calculates what "clothes" each element should wearCSSOM (CSS Object Model) is a tree structure that the browser converts CSS rules into, used to calculate the final style of each element. You can think of it as a wardrobe styling guide: - Upper-level rules (body font) affect lower levels (all child elements) - If there are conflicts (e.g., multiple rules specify different colors for the same element), they're resolved by "specificity" - Ultimately, it calculates what "clothes" each element should wear The CSSOM construction process is similar to the DOM, but with one key difference: CSS is "inherited" and "cascading."The CSSOM construction process is similar to the DOM, but with one key difference: CSS is "inherited" and "cascading." Original CSS: `` Pitfall 1: CSS Selector Specificity ConflictsPitfall 1: CSS Selector Specificity Conflicts `` Pitfall 2: Unclosed HTML Tags โ The Browser "Auto-Repairs"Pitfall 2: Unclosed HTML Tags โ The Browser "Auto-Repairs" `` This is some text This is some text This is some text This is some text ------ You might ask: "We already have the DOM tree and CSSOM tree, why build yet another render tree? Can't we just use the DOM directly?"You might ask: "We already have the DOM tree and CSSOM tree, why build yet another render tree? Can't we just use the DOM directly?" The answer is: the DOM tree contains too much "useless" information.The answer is: the DOM tree contains too much "useless" information. For example, consider this HTML:For example, consider this HTML: The DOM tree includes all elements:The DOM tree includes all elements: But the render tree only includes elements that "need to be drawn on screen":But the render tree only includes elements that "need to be drawn on screen": When building the render tree, the browser follows a set of rules:When building the render tree, the browser follows a set of rules: Key finding: Many people think that after setting `` ------ Layout, also called Reflow, is the process where the browser calculates "where each element is and how much space it occupies" in the render tree. You can think of it as an interior designer measuring a room: - First measure the length and width of each room - Decide where furniture goes - Calculate the coordinates of each piece of furniture Why is layout "expensive"? Because a change to one element can affect other elements. For example, if you widen a div, the div next to it might get pushed down, causing the entire page to recalculate.Layout, also called Reflow, is the process where the browser calculates "where each element is and how much space it occupies" in the render tree. You can think of it as an interior designer measuring a room: - First measure the length and width of each room - Decide where furniture goes - Calculate the coordinates of each piece of furniture Why is layout "expensive"? Because a change to one element can affect other elements. For example, if you widen a div, the div next to it might get pushed down, causing the entire page to recalculate. Here are common operations that trigger reflow โ recommended to bookmark and memorize:Here are common operations that trigger reflow โ recommended to bookmark and memorize: Key findings: 1. Geometric properties (width, height, position) are the most expensive: They trigger a full layout recalculation 2. Querying properties is more dangerous than modifying them: Reading Pitfall: Animating with widthPitfall: Animating with width `` Forced Synchronous Layout, also known as Layout Thrashing, is the most common and most severe performance problem. It happens because: when JavaScript reads a layout property (like `` ------ Paint is the process where the browser actually "draws" the layout-calculated elements onto the screen. You can think of it as painting a room: - Layout stage = measuring dimensions, drawing lines - Paint stage = actually applying paint, putting up wallpaper Paint is not as expensive as layout, but it's not cheap either. Frequent painting still affects performance, especially for complex elements (shadows, gradients, etc.).Paint is the process where the browser actually "draws" the layout-calculated elements onto the screen. You can think of it as painting a room: - Layout stage = measuring dimensions, drawing lines - Paint stage = actually applying paint, putting up wallpaper Paint is not as expensive as layout, but it's not cheap either. Frequent painting still affects performance, especially for complex elements (shadows, gradients, etc.). Unlike reflow, repaint only involves "appearance" changes, not "geometric" changes:Unlike reflow, repaint only involves "appearance" changes, not "geometric" changes: Key finding: Pitfall: Using box-shadow for hover animationPitfall: Using box-shadow for hover animation `` ------ Compositing is the "magic" of modern browsers. It divides different parts of the page into multiple layers and uses the GPU (Graphics Processing Unit) to composite the final image in parallel. You can think of it as Photoshop layers: - Traditional approach = everything drawn on a single layer (CPU serial, slow) - Compositing approach = draw in layers, then merge (GPU parallel, fast) Why is compositing fast? Because GPUs excel at "image compositing" โ parallel tasks that they can do dozens of times faster than CPUs.Compositing is the "magic" of modern browsers. It divides different parts of the page into multiple layers and uses the GPU (Graphics Processing Unit) to composite the final image in parallel. You can think of it as Photoshop layers: - Traditional approach = everything drawn on a single layer (CPU serial, slow) - Compositing approach = draw in layers, then merge (GPU parallel, fast) Why is compositing fast? Because GPUs excel at "image compositing" โ parallel tasks that they can do dozens of times faster than CPUs. The browser automatically promotes certain elements to independent compositing layers. Here are the common triggers:The browser automatically promotes certain elements to independent compositing layers. Here are the common triggers: Key finding: Some people hear "GPU acceleration is fast" and add `` ------ The Event Loop is the mechanism JavaScript uses to achieve "asynchrony." Because JavaScript is single-threaded (it can only do one thing at a time), but it needs to handle user clicks, network requests, timers, and other tasks, it requires a "scheduling system" to manage these tasks. You can think of it as a package sorting center: - Call Stack = the package currently being processed - Web APIs = external partner warehouses (timers, network requests, etc.) - Callback Queue = shelves of pending packages - Event Loop = the sorting robot (constantly checking "can the next task be processed?")The Event Loop is the mechanism JavaScript uses to achieve "asynchrony." Because JavaScript is single-threaded (it can only do one thing at a time), but it needs to handle user clicks, network requests, timers, and other tasks, it requires a "scheduling system" to manage these tasks. You can think of it as a package sorting center: - Call Stack = the package currently being processed - Web APIs = external partner warehouses (timers, network requests, etc.) - Callback Queue = shelves of pending packages - Event Loop = the sorting robot (constantly checking "can the next task be processed?") Early JavaScript only had a single task queue. But as asynchronous programming became more complex, browsers introduced two types of tasks:Early JavaScript only had a single task queue. But as asynchronous programming became more complex, browsers introduced two types of tasks: The "mnemonic" for execution order:The "mnemonic" for execution order: Many people think `` Microtasks are "more urgent" than macrotasks. If you want an operation to execute "right after the current code block ends, but before UI updates," use ------ Now that you understand the rendering pipeline workflow, let's look at how to optimize. Here are the five most practical optimization techniques.Now that you understand the rendering pipeline workflow, let's look at how to optimize. Here are the five most practical optimization techniques. Problem: Interleaving reads and writes of layout properties causes layout thrashing.Problem: Interleaving reads and writes of layout properties causes layout thrashing. `` Problem: Animating with `` Problem: When the number of list items reaches thousands, too many DOM nodes cause performance issues.Problem: When the number of list items reaches thousands, too many DOM nodes cause performance issues. Core idea: Only render the list items visible within the viewport (plus a small buffer), keeping the DOM node count fixed regardless of total data size.Core idea: Only render the list items visible within the viewport (plus a small buffer), keeping the DOM node count fixed regardless of total data size. `` Problem: Frequently triggered events (like scroll, resize) cause performance issues.Problem: Frequently triggered events (like scroll, resize) cause performance issues. `` Problem: Loading too many resources on the first screen makes the page open slowly.Problem: Loading too many resources on the first screen makes the page open slowly. `` ------ After understanding the browser's rendering pipeline, you should be able to identify these common performance issues:After understanding the browser's rendering pipeline, you should be able to identify these common performance issues: If you've carefully read each chapter's "Pitfall Journal," you've also mastered these core concepts:If you've carefully read each chapter's "Pitfall Journal," you've also mastered these core concepts: These concepts will help you quickly identify performance bottlenecks.These concepts will help you quickly identify performance bottlenecks. - "Animation is choppy โ check if it's triggering reflow or repaint" - "Scroll performance is poor โ may need throttling or requestAnimationFrame" - "Large lists stutter โ need virtual scrolling" - "Frequent style changes cause performance issues โ please optimize with transform"- "Animation is choppy โ check if it's triggering reflow or repaint" - "Scroll performance is poor โ may need throttling or requestAnimationFrame" - "Large lists stutter โ need virtual scrolling" - "Frequent style changes cause performance issues โ please optimize with transform" ------ Through this article, we can draw the following core conclusions:Through this article, we can draw the following core conclusions: From a practical standpoint: It's not about doing more optimization, but about doing the right optimization. Understanding the browser's rendering pipeline tells you where to focus effort and where to let go.From a practical standpoint: It's not about doing more optimization, but about doing the right optimization. Understanding the browser's rendering pipeline tells you where to focus effort and where to let go. From a cost perspective:From a cost perspective: The goal is: under given browser and hardware conditions, ensure every rendering step's investment delivers clear performance returns.The goal is: under given browser and hardware conditions, ensure every rendering step's investment delivers clear performance returns. ------) - Below are the "children" (, ) - Further down are the "grandchildren" (, ) Why convert to a tree? Because tree structures are great for "searching" and "modifying." For example, if you want to find "all elements with class title," the browser can quickly search the tree instead of slowly scanning through a mess of text.DOM (Document Object Model) is a tree structure that the browser converts the HTML document into, making it easy for JavaScript to manipulate page elements. You can think of it as a family tree: - The top is the "ancestor" () - Below are the "children" (, ) - Further down are the "grandchildren" (, ) Why convert to a tree? Because tree structures are great for "searching" and "modifying." For example, if you want to find "all elements with class title," the browser can quickly search the tree instead of slowly scanning through a mess of text.
html <div class="container"> <p>Hello World</p> </div>
โ "end tag div" โ "end tag div"class="container" โ "attribute class, value container"class="container" โ "attribute class, value container" โ "start tag p" โ "start tag p"Hello World โ "text content"Hello World โ "text content" โ "end tag p" โ "end tag p"
Element nodes:
class="container"Attribute nodes: class="container""Hello World"Text nodes: "Hello World"CODE Document (document root node) โโโ html โโโ body โโโ div.class = "container" โโโ p โโโ "Hello World"
3.2 The CSSOM Tree: The "Rulebook" for Styles3.2 The CSSOM Tree: The "Rulebook" for Styles
css body { font-size: 16px; color: #333; } .container { width: 100%; color: red; / will override body's color / } .container p { font-weight: bold; } ` Constructed CSSOM Tree: ` StyleSheet โโโ body โ โโโ font-size: 16px โ โโโ color: #333 โโโ .container โโโ width: 100% โโโ color: red (higher specificity, overrides body's color) โโโ p โโโ font-weight: bold ``Original CSS: ``css body { font-size: 16px; color: #333; } .container { width: 100%; color: red; / will override body's color / } .container p { font-weight: bold; } ` Constructed CSSOM Tree: ` StyleSheet โโโ body โ โโโ font-size: 16px โ โโโ color: #333 โโโ .container โโโ width: 100% โโโ color: red (higher specificity, overrides body's color) โโโ p โโโ font-weight: bold ``3.3 Case: My CSS "Take Effect"3.3 Case: My CSS "Take Effect"
css / The CSS you wrote / #header { color: red; } / id selector, specificity 100 / .title { color: blue; } / class selector, specificity 10 / / HTML / `` You thought it would be blue, but it's red. Because the id selector's specificity (100) is higher than the class selector's (10).``css / The CSS you wrote / #header { color: red; } / id selector, specificity 100 / .title { color: blue; } / class selector, specificity 10 / / HTML / `` You thought it would be blue, but it's red. Because the id selector's specificity (100) is higher than the class selector's (10).html `` The browser is very "forgiving" and will automatically fix your errors. But this tolerance comes at a cost โ the browser needs extra computation to guess your intent, which affects performance.``html `` The browser is very "forgiving" and will automatically fix your errors. But this tolerance comes at a cost โ the browser needs extra computation to guess your intent, which affects performance.4. Stage 2: Building the Render Tree4. Stage 2: Building the Render Tree
4.1 Motivation for needing a "Render Tree"4.1 Motivation for needing a "Render Tree"
html <html> <head> <title>Page Title</title> <style>/* CSS code */</style> <script>/* JavaScript code */</script> </head> <body> <div class="container"> <p>Visible content</p> </div> <div style="display: none"> <p>Hidden content (display:none)</p> </div> </body> </html>
, , , (these don't display), , , (these don't display)display: none div (also doesn't display)The display: none div (also doesn't display)
and its childrenRemoves and its childrendisplay: none divRemoves the display: none div4.2 Render Tree Construction Rules4.2 Render Tree Construction Rules
Scenario Handling Example Performance Impact display: noneCompletely excluded from render tree Element and its children are all invisible โ
Reduces rendering workload visibility: hiddenIncluded in render tree, but not painted Occupies space, but fully transparent โ ๏ธ Still requires layout calculation opacity: 0Included in render tree, but transparent Interactive (clickable), but invisible โ ๏ธ Still requires layout calculation Outside viewport Included in render tree, not painted yet Painted only when scrolled into view โ ๏ธ But still in the render tree display: none is the only hiding method that "truly saves performance," because the element is completely absent from the render tree, and the browser won't do any layout or paint work for it. In contrast, visibility: hidden and opacity: 0 are "invisible" but still in the render tree, so the browser still needs to calculate their layout (they occupy space). If you need to "hide without affecting layout" (e.g., for fade-in/fade-out animations), use opacity; if you need to "completely hide and not occupy space," use display: none.Key finding: display: none is the only hiding method that "truly saves performance," because the element is completely absent from the render tree, and the browser won't do any layout or paint work for it. In contrast, visibility: hidden and opacity: 0 are "invisible" but still in the render tree, so the browser still needs to calculate their layout (they occupy space). If you need to "hide without affecting layout" (e.g., for fade-in/fade-out animations), use opacity; if you need to "completely hide and not occupy space," use display: none.4.3 Case: Page Lag After Setting display:none4.3 Case: Page Lag After Setting display:none
display: none, the element "disappears" and no operations on it will affect performance. This is wrong! Although display: none elements are not in the render tree, when you modify their properties via JavaScript, the browser still needs to: 1. Recalculate styles (match CSS rules) 2. Track changes (prepare for future display) Look at this "optimization" example:Many people think that after setting display: none, the element "disappears" and no operations on it will affect performance. This is wrong! Although display: none elements are not in the render tree, when you modify their properties via JavaScript, the browser still needs to: 1. Recalculate styles (match CSS rules) 2. Track changes (prepare for future display) Look at this "optimization" example:javascript // โ The "optimization" you thought: hide first, modify, then show const container = document.getElementById('list') container.style.display = 'none' // Aggressively manipulate the DOM for (let i = 0; i < 1000; i++) { const item = document.createElement('div') item.style.width = Math.random() * 100 + 'px' // Changing width! item.textContent = Item ${i} container.appendChild(item) } container.style.display = 'block' // Problem: every time style.width is modified, the browser recalculates styles, // even though the element is display:none! ` โ
The correct optimization approach: `javascript // Use DocumentFragment for batch operations const container = document.getElementById('list') const fragment = document.createDocumentFragment() // Virtual container // All operations happen on the in-memory fragment for (let i = 0; i < 1000; i++) { const item = document.createElement('div') item.style.width = Math.random() * 100 + 'px' item.textContent = Item ${i} fragment.appendChild(item) // Doesn't affect the real DOM } // Insert into real DOM once, triggering only a single render container.appendChild(fragment) ````javascript // โ The "optimization" you thought: hide first, modify, then show const container = document.getElementById('list') container.style.display = 'none' // Aggressively manipulate the DOM for (let i = 0; i < 1000; i++) { const item = document.createElement('div') item.style.width = Math.random() * 100 + 'px' // Changing width! item.textContent = Item ${i} container.appendChild(item) } container.style.display = 'block' // Problem: every time style.width is modified, the browser recalculates styles, // even though the element is display:none! ` โ
The correct optimization approach: `javascript // Use DocumentFragment for batch operations const container = document.getElementById('list') const fragment = document.createDocumentFragment() // Virtual container // All operations happen on the in-memory fragment for (let i = 0; i < 1000; i++) { const item = document.createElement('div') item.style.width = Math.random() * 100 + 'px' item.textContent = Item ${i} fragment.appendChild(item) // Doesn't affect the real DOM } // Insert into real DOM once, triggering only a single render container.appendChild(fragment) ``5. Stage 3: Layout and Reflow5. Stage 3: Layout and Reflow
5.1 Overview of "Layout"5.1 Overview of "Layout"
5.2 "Minefields" That Trigger Reflow5.2 "Minefields" That Trigger Reflow
Category Property/Operation Performance Impact Alternative Dimensions width, height, min/max-width/height๐๐๐ Use transform: scale() insteadPosition top, right, bottom, left๐๐๐ Use transform: translate() insteadMargins margin, padding๐๐ Use transform or gap insteadBorders border-width๐๐ Avoid frequent changes Content Text content changes, image loading ๐๐ Reserve space to avoid layout shift Fonts font-size, line-height๐๐๐ Avoid frequent changes Display display value changes๐๐๐ Use visibility or opacity instead (if full hiding isn't needed)Queries offsetWidth, offsetHeight, etc.๐๐๐๐๐ Batch reads to avoid layout thrashing offsetWidth forces synchronous layout (see section 5.4) 3. transform and opacity have the best performance: They don't trigger reflow, only compositingKey findings: 1. Geometric properties (width, height, position) are the most expensive: They trigger a full layout recalculation 2. Querying properties is more dangerous than modifying them: Reading offsetWidth forces synchronous layout (see section 5.4) 3. transform and opacity have the best performance: They don't trigger reflow, only compositing5.3 Case: Animation Choppy Like a Slideshow5.3 Case: Animation Choppy Like a Slideshow
css / โ Bad animation: triggers reflow / .box { width: 100px; transition: width 0.3s; } .box:hover { width: 200px; / Changing width triggers reflow! / } ` Every frame of the animation triggers reflow. The browser needs to: 1. Recalculate the width 2. Recalculate the position (may affect other elements) 3. Repaint โ
Good animation: use transform `css / โ
Good animation: only triggers compositing / .box { width: 100px; transform: scaleX(1); transition: transform 0.3s; } .box:hover { transform: scaleX(2); / Scaling doesn't trigger reflow! / } ` transform` is handled directly by the GPU, doesn't trigger reflow or repaint, and the animation is buttery smooth.``css / โ Bad animation: triggers reflow / .box { width: 100px; transition: width 0.3s; } .box:hover { width: 200px; / Changing width triggers reflow! / } ` Every frame of the animation triggers reflow. The browser needs to: 1. Recalculate the width 2. Recalculate the position (may affect other elements) 3. Repaint โ
Good animation: use transform `css / โ
Good animation: only triggers compositing / .box { width: 100px; transform: scaleX(1); transition: transform 0.3s; } .box:hover { transform: scaleX(2); / Scaling doesn't trigger reflow! / } ` transform` is handled directly by the GPU, doesn't trigger reflow or repaint, and the animation is buttery smooth.5.4 Performance Killer: Forced Synchronous Layout5.4 Performance Killer: Forced Synchronous Layout
offsetWidth), the browser must immediately execute layout calculation to return an accurate value. If you "interleave reads and writes," you force the browser to repeatedly "layout โ read โ layout โ read," creating a vicious cycle.Forced Synchronous Layout, also known as Layout Thrashing, is the most common and most severe performance problem. It happens because: when JavaScript reads a layout property (like offsetWidth), the browser must immediately execute layout calculation to return an accurate value. If you "interleave reads and writes," you force the browser to repeatedly "layout โ read โ layout โ read," creating a vicious cycle.javascript // โ Terrible: interleaved reads and writes cause layout thrashing const elements = document.querySelectorAll('.item') for (let i = 0; i < elements.length; i++) { const height = elements[i].offsetHeight // Read โ forces layout elements[i].style.width = (height * 2) + 'px' // Write โ marks as needing reflow // The next iteration's read forces layout again... vicious cycle! } // With 100 elements, this triggers 100 layout calculations! ` โ
The correct optimization: separate reads and writes `javascript const elements = document.querySelectorAll('.item') // Step 1: Batch reads (read everything first) const heights = [] for (let i = 0; i < elements.length; i++) { heights.push(elements[i].offsetHeight) // Only triggers layout once } // Step 2: Batch writes (write everything after) requestAnimationFrame(() => { for (let i = 0; i < elements.length; i++) { elements[i].style.width = (heights[i] * 2) + 'px' // Only triggers reflow once } }) ````javascript // โ Terrible: interleaved reads and writes cause layout thrashing const elements = document.querySelectorAll('.item') for (let i = 0; i < elements.length; i++) { const height = elements[i].offsetHeight // Read โ forces layout elements[i].style.width = (height * 2) + 'px' // Write โ marks as needing reflow // The next iteration's read forces layout again... vicious cycle! } // With 100 elements, this triggers 100 layout calculations! ` โ
The correct optimization: separate reads and writes `javascript const elements = document.querySelectorAll('.item') // Step 1: Batch reads (read everything first) const heights = [] for (let i = 0; i < elements.length; i++) { heights.push(elements[i].offsetHeight) // Only triggers layout once } // Step 2: Batch writes (write everything after) requestAnimationFrame(() => { for (let i = 0; i < elements.length; i++) { elements[i].style.width = (heights[i] * 2) + 'px' // Only triggers reflow once } }) ``6. Stage 4: Paint and Repaint6. Stage 4: Paint and Repaint
6.1 Overview of "Paint"6.1 Overview of "Paint"
6.2 Signals That Trigger Repaint6.2 Signals That Trigger Repaint
Category Property Performance Impact Notes Color color, background-color๐ The most common repaint trigger Background background-image, background-position๐๐ Images are slower than solid colors Border border-color, border-style๐ Changing border color/style Text text-decoration, text-shadow๐๐ Shadows are slower than plain text Box Shadow box-shadow๐๐๐ Complex shadows are very slow Border Radius border-radius๐ Changing corner roundness Opacity opacityโ
Special: doesn't trigger repaint, only compositing opacity is special! Like transform, it doesn't trigger repaint โ it directly triggers the compositing stage. This is why using opacity for fade-in/fade-out animations has the best performance. Also, shadows and gradients are more expensive than repaint because they require complex pixel calculations. If your page has many box-shadows, consider using pseudo-elements or images instead.Key finding: opacity is special! Like transform, it doesn't trigger repaint โ it directly triggers the compositing stage. This is why using opacity for fade-in/fade-out animations has the best performance. Also, shadows and gradients are more expensive than repaint because they require complex pixel calculations. If your page has many box-shadows, consider using pseudo-elements or images instead.6.3 Case: Hover Effect Stuttering6.3 Case: Hover Effect Stuttering
css / โ Bad hover effect: box-shadow animation is very slow / .card { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); transition: box-shadow 0.3s; } .card:hover { box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); / Shadows are slow! / } ` box-shadow requires per-pixel calculation, causing stutter during animation. โ
Good approach: use transform or pseudo-elements `css / โ
Good hover effect: use transform / .card { transform: translateY(0); transition: transform 0.3s, box-shadow 0.3s; } .card:hover { transform: translateY(-4px); / Only change shadow on hover, don't animate it / box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); } ````css / โ Bad hover effect: box-shadow animation is very slow / .card { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); transition: box-shadow 0.3s; } .card:hover { box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); / Shadows are slow! / } ` box-shadow requires per-pixel calculation, causing stutter during animation. โ
Good approach: use transform or pseudo-elements `css / โ
Good hover effect: use transform / .card { transform: translateY(0); transition: transform 0.3s, box-shadow 0.3s; } .card:hover { transform: translateY(-4px); / Only change shadow on hover, don't animate it / box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); } ``7. Stage 5: Compositing and GPU Acceleration7. Stage 5: Compositing and GPU Acceleration
7.1 Overview of "Compositing"7.1 Overview of "Compositing"
7.2 Criteria for Element Promotion to Compositing Layers7.2 Criteria for Element Promotion to Compositing Layers
Trigger Condition CSS Property/Value Performance Impact Notes 3D Transform transform: translate3d(), rotate3d()โ
โ
โ
Best animation performance Hardware Acceleration Hack transform: translateZ(0)โ
โ
Commonly called "force GPU acceleration" Opacity Animation opacity change (with animation)โ
โ
โ
Doesn't trigger repaint Fixed Positioning position: fixedโ
Avoids repeated layout on scroll Will-Change will-change: transform, opacityโ
โ
Creates layer in advance; watch memory Canvas/WebGL , WebGL contentโ
โ
Naturally in independent layers Video โ
โ
Independent layer, prevents interference transform and opacity are the best-performing animation properties because they don't trigger reflow or repaint โ they directly trigger compositing. This is why performance optimization guides always say "use transform and opacity for animations." But be careful: each compositing layer consumes GPU memory. Abusing translateZ(0) can cause memory explosions (see section 7.4).Key finding: transform and opacity are the best-performing animation properties because they don't trigger reflow or repaint โ they directly trigger compositing. This is why performance optimization guides always say "use transform and opacity for animations." But be careful: each compositing layer consumes GPU memory. Abusing translateZ(0) can cause memory explosions (see section 7.4).7.3 Case: Too Many Compositing Layers Making It Slower7.3 Case: Too Many Compositing Layers Making It Slower
transform: translateZ(0) to every element, only to find the page is even slower. The problem: Each compositing layer needs to store a "texture" (bitmap) in GPU memory. If a page has 100 compositing layers, GPU memory can be overwhelmed, causing low-end devices to crash or fall back to CPU rendering.Some people hear "GPU acceleration is fast" and add transform: translateZ(0) to every element, only to find the page is even slower. The problem: Each compositing layer needs to store a "texture" (bitmap) in GPU memory. If a page has 100 compositing layers, GPU memory can be overwhelmed, causing low-end devices to crash or fall back to CPU rendering.css / โ Wrong approach: enable GPU acceleration on every element / .card { transform: translateZ(0); } .button { transform: translateZ(0); } .icon { transform: translateZ(0); } / ... 100 elements all get it ... / / Result: GPU memory explosion, page freezes / ` โ
The correct approach: use on demand `css / Strategy 1: Only enable on elements that truly need animation / .card { transition: transform 0.3s ease; } .card:hover { transform: translateY(-5px); / Automatically creates a compositing layer / } / Strategy 2: Use will-change to hint the browser / .card { will-change: transform; / Create layer in advance / } / Strategy 3: Remove after animation ends / .card:not(:hover) { will-change: auto; / Release GPU memory / } ````css / โ Wrong approach: enable GPU acceleration on every element / .card { transform: translateZ(0); } .button { transform: translateZ(0); } .icon { transform: translateZ(0); } / ... 100 elements all get it ... / / Result: GPU memory explosion, page freezes / ` โ
The correct approach: use on demand `css / Strategy 1: Only enable on elements that truly need animation / .card { transition: transform 0.3s ease; } .card:hover { transform: translateY(-5px); / Automatically creates a compositing layer / } / Strategy 2: Use will-change to hint the browser / .card { will-change: transform; / Create layer in advance / } / Strategy 3: Remove after animation ends / .card:not(:hover) { will-change: auto; / Release GPU memory / } ``8. Event Loop: JavaScript's "Cloning Technique"8. Event Loop: JavaScript's "Cloning Technique"
8.1 Macrotasks and Microtasks8.1 Macrotasks and Microtasks
Type Common Sources Priority Execution Timing Macrotask setTimeout/setInterval, I/O operations, UI renderingLow One per event loop cycle Microtask Promise.then, MutationObserverHigh After the current macrotask ends, immediately flush all microtasks CODE 1. Execute the current macrotask (e.g., the entire <script>) 2. Execute all microtasks generated during execution (Promise.then, etc.) โณ Microtasks can spawn new microtasks โ all are flushed before continuing 3. If needed, perform UI rendering (reflow/repaint) 4. Start the next event loop cycle, execute the next macrotask
8.2 Case: Promise vs setTimeout Execution Speed8.2 Case: Promise vs setTimeout Execution Speed
setTimeout(fn, 0) means "execute immediately after 0 milliseconds." This is a wrong understanding. In reality, setTimeout(fn, 0) means: "after waiting at least 0 milliseconds, add the callback to the macrotask queue." But it still needs to wait for the current call stack to clear, the microtask queue to flush, and possible UI rendering to complete before it can execute.Many people think setTimeout(fn, 0) means "execute immediately after 0 milliseconds." This is a wrong understanding. In reality, setTimeout(fn, 0) means: "after waiting at least 0 milliseconds, add the callback to the macrotask queue." But it still needs to wait for the current call stack to clear, the microtask queue to flush, and possible UI rendering to complete before it can execute.javascript console.log('1. Start') setTimeout(() => { console.log('2. setTimeout callback') }, 0) Promise.resolve().then(() => { console.log('3. Promise.then') }) console.log('4. End') // The output order you might expect: // 1. Start // 4. End // 2. setTimeout callback โ Isn't setTimeout(0) immediate? // 3. Promise.then // The actual output order: // 1. Start // 4. End // 3. Promise.then โ Promise.then executes before setTimeout! // 2. setTimeout callback ` Execution Flow Diagram: ` Call Stack Macrotask Queue Microtask Queue [setTimeout callback] [Promise.then callback] 1. console.log('1. Start') โ Output: 1. Start 2. setTimeout(fn, 0) โ Add callback to macrotask queue โ [setTimeout callback] 3. Promise.resolve().then() โ Add callback to microtask queue โ [Promise.then callback] 4. console.log('4. End') โ Output: 4. End 5. Call stack clears, check microtask queue โ Found Promise.then callback โ Execute: console.log('3. Promise.then') โ Output: 3. Promise.then 6. Microtask queue flushed โ May need UI rendering (if there are changes) 7. Check macrotask queue โ Found setTimeout callback โ Execute: console.log('2. setTimeout callback') โ Output: 2. setTimeout callback ````javascript console.log('1. Start') setTimeout(() => { console.log('2. setTimeout callback') }, 0) Promise.resolve().then(() => { console.log('3. Promise.then') }) console.log('4. End') // The output order you might expect: // 1. Start // 4. End // 2. setTimeout callback โ Isn't setTimeout(0) immediate? // 3. Promise.then // The actual output order: // 1. Start // 4. End // 3. Promise.then โ Promise.then executes before setTimeout! // 2. setTimeout callback ` Execution Flow Diagram: ` Call Stack Macrotask Queue Microtask Queue [setTimeout callback] [Promise.then callback] 1. console.log('1. Start') โ Output: 1. Start 2. setTimeout(fn, 0) โ Add callback to macrotask queue โ [setTimeout callback] 3. Promise.resolve().then() โ Add callback to microtask queue โ [Promise.then callback] 4. console.log('4. End') โ Output: 4. End 5. Call stack clears, check microtask queue โ Found Promise.then callback โ Execute: console.log('3. Promise.then') โ Output: 3. Promise.then 6. Microtask queue flushed โ May need UI rendering (if there are changes) 7. Check macrotask queue โ Found setTimeout callback โ Execute: console.log('2. setTimeout callback') โ Output: 2. setTimeout callback ``Promise.then or queueMicrotask. setTimeout(0) does not guarantee immediate execution โ it will be delayed at least until the current call stack clears and the microtask queue is flushed.Microtasks are "more urgent" than macrotasks. If you want an operation to execute "right after the current code block ends, but before UI updates," use Promise.then or queueMicrotask. setTimeout(0) does not guarantee immediate execution โ it will be delayed at least until the current call stack clears and the microtask queue is flushed.9. Performance Optimization in Practice: Make Your Web Pages "Fly"9. Performance Optimization in Practice: Make Your Web Pages "Fly"
9.1 The Golden Rule: Avoid Forced Synchronous Layout9.1 The Golden Rule: Avoid Forced Synchronous Layout
javascript // โ Terrible: interleaved reads and writes cause layout thrashing for (let i = 0; i < elements.length; i++) { const height = elements[i].offsetHeight // Read โ forces layout elements[i].style.height = (height * 2) + 'px' // Write โ marks as needing reflow // The next iteration's read forces layout again... vicious cycle! } // โ
Excellent: read everything first, then write everything // Step 1: Batch reads const heights = [] for (let i = 0; i < elements.length; i++) { heights.push(elements[i].offsetHeight) } // Step 2: Batch writes requestAnimationFrame(() => { for (let i = 0; i < elements.length; i++) { elements[i].style.height = (heights[i] * 2) + 'px' } }) ````javascript // โ Terrible: interleaved reads and writes cause layout thrashing for (let i = 0; i < elements.length; i++) { const height = elements[i].offsetHeight // Read โ forces layout elements[i].style.height = (height * 2) + 'px' // Write โ marks as needing reflow // The next iteration's read forces layout again... vicious cycle! } // โ
Excellent: read everything first, then write everything // Step 1: Batch reads const heights = [] for (let i = 0; i < elements.length; i++) { heights.push(elements[i].offsetHeight) } // Step 2: Batch writes requestAnimationFrame(() => { for (let i = 0; i < elements.length; i++) { elements[i].style.height = (heights[i] * 2) + 'px' } }) ``9.2 Use transform and opacity for Animations9.2 Use transform and opacity for Animations
width, height, left, top triggers reflow.Problem: Animating with width, height, left, top triggers reflow.css / โ Bad animation: triggers reflow / .box { transition: width 0.3s, left 0.3s; } .box.moving { width: 200px; left: 100px; } / โ
Good animation: only triggers compositing / .box { transition: transform 0.3s; } .box.moving { transform: translateX(100px) scaleX(2); } ````css / โ Bad animation: triggers reflow / .box { transition: width 0.3s, left 0.3s; } .box.moving { width: 200px; left: 100px; } / โ
Good animation: only triggers compositing / .box { transition: transform 0.3s; } .box.moving { transform: translateX(100px) scaleX(2); } ``9.3 Virtual Scrolling: Solving Large Data Lists9.3 Virtual Scrolling: Solving Large Data Lists
vue ````vue ``9.4 Debounce and Throttle: Reduce Event Trigger Frequency9.4 Debounce and Throttle: Reduce Event Trigger Frequency
javascript // Debounce: delay execution; if triggered again within the delay, restart the timer function debounce(fn, delay) { let timer = null return function (...args) { clearTimeout(timer) timer = setTimeout(() => fn.apply(this, args), delay) } } // Throttle: execute at fixed time intervals function throttle(fn, interval) { let lastTime = 0 return function (...args) { const now = Date.now() if (now - lastTime >= interval) { lastTime = now fn.apply(this, args) } } } // Usage example window.addEventListener('scroll', debounce(handleScroll, 200)) window.addEventListener('resize', throttle(handleResize, 100)) ````javascript // Debounce: delay execution; if triggered again within the delay, restart the timer function debounce(fn, delay) { let timer = null return function (...args) { clearTimeout(timer) timer = setTimeout(() => fn.apply(this, args), delay) } } // Throttle: execute at fixed time intervals function throttle(fn, interval) { let lastTime = 0 return function (...args) { const now = Date.now() if (now - lastTime >= interval) { lastTime = now fn.apply(this, args) } } } // Usage example window.addEventListener('scroll', debounce(handleScroll, 200)) window.addEventListener('resize', throttle(handleResize, 100)) ``9.5 Lazy Loading: Defer Loading Non-Critical Resources9.5 Lazy Loading: Defer Loading Non-Critical Resources
javascript // Image lazy loading const lazyImages = document.querySelectorAll('img[data-src]') const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target img.src = img.dataset.src // Load the real image img.removeAttribute('data-src') observer.unobserve(img) // Stop observing } }) }) lazyImages.forEach(img => imageObserver.observe(img)) ````javascript // Image lazy loading const lazyImages = document.querySelectorAll('img[data-src]') const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target img.src = img.dataset.src // Load the real image img.removeAttribute('data-src') observer.unobserve(img) // Stop observing } }) }) lazyImages.forEach(img => imageObserver.observe(img)) ``10. Performance Problems You Should Now Be Able to Identify10. Performance Problems You Should Now Be Able to Identify
Problem Code What's Wrong How to Describe It to AI element.style.width = ...Frequently modifying width in a loop "This triggers multiple reflows; please use transform or batch processing instead" height = element.offsetHeightReading layout properties right after writing "This is forced synchronous layout; please separate reads and writes" element.className = ...Frequently modifying class triggers style recalculation "Use classList.add/remove instead to reduce style calculations" Animating with width/leftTriggers reflow and repaint, poor performance "Use transform and opacity for animations instead" Adding translateZ(0) to all elementsAbusing GPU acceleration causes memory explosion "Only enable GPU acceleration on elements that need animation" Rendering 10,000 list items all at once Too many DOM nodes cause stutter "Implement virtual scrolling to only render the visible area" Manipulating DOM directly in scroll events Too-high trigger frequency causes stutter "Use requestAnimationFrame or throttle to optimize" Using box-shadow for hover animationComplex shadow calculation is very slow "Use transform or pseudo-elements instead; avoid animating shadows"
11. Summary: The Essence of Rendering Pipeline Optimization11. Summary: The Essence of Rendering Pipeline Optimization
transform and opacityComplex animation effects that trigger reflow and repaint often stem from using the "wrong properties" and need to be solved through transform and opacity12. Glossary12. Glossary
English Term Chinese Translation Explanation DOM ๆๆกฃๅฏน่ฑกๆจกๅ The tree structure formed after the browser parses an HTML document; JavaScript can manipulate page elements through the DOM API CSSOM CSSๅฏน่ฑกๆจกๅ The tree structure formed after the browser parses CSS; combined with the DOM to calculate final styles Render Tree ๆธฒๆๆ Formed by merging the DOM tree and CSSOM tree; contains only visible nodes, used for subsequent layout calculation and painting Layout ๅธๅฑ The process of calculating geometric information (position, size) for each node in the render tree; also called Reflow Reflow ้ๆ/ๅๆต When an element's geometric properties (size, position) change, the browser must recalculate layout Paint ็ปๅถ/้็ป The process of drawing layout-calculated element styles (color, background, borders, etc.) onto the screen Repaint ้็ป A paint update triggered when an element's appearance properties (like color, background) change without affecting geometric properties Composite ๅๆ The process of merging multiple paint layers into the final screen image, typically executed on the GPU Layer ๅฑ/ๅๆๅฑ An independent paint surface created by the browser to optimize rendering; can be transformed and composited independently Event Loop ไบไปถๅพช็ฏ JavaScript's asynchronous execution mechanism, responsible for scheduling macrotask and microtask execution Call Stack ่ฐ็จๆ A data structure that records the currently executing JavaScript functions Macro Task ๅฎไปปๅก Lower-priority task types in the event loop, such as setTimeout, setInterval, I/O operations, etc. Micro Task ๅพฎไปปๅก Higher-priority task types in the event loop, such as Promise.then, MutationObserver, etc. Forced Synchronous Layout ๅผบๅถๅๆญฅๅธๅฑ A performance problem where interleaving reads and writes of layout properties in JavaScript forces the browser to immediately execute layout calculations Layout Thrashing ๅธๅฑๆๅจ The severe performance degradation caused by frequent forced synchronous layout Virtual Scrolling ่ๆๆปๅจ A technique that only renders visible list items within the viewport, used to optimize performance for large data lists RAF ่ฏทๆฑๅจ็ปๅธง A browser API for executing animation-related JavaScript code before the next repaint