Vue3 Compilation Optimization: PatchFlag
Description
PatchFlag is an optimization technique introduced by Vue3 during the compilation stage to improve the performance of runtime virtual DOM diffing. In Vue2, when a component's state changes, a full comparison (full diff) between the old and new virtual DOM trees is required. Vue3's compiler performs static analysis during template compilation and marks nodes that change dynamically with different types of flags (i.e., PatchFlags). During runtime, the renderer can quickly locate the dynamic content that needs updating based on these flags, thereby skipping comparisons of a large number of unnecessary static nodes.
Process
-
Static Analysis During Compilation
- When Vue3's compiler processes a template (e.g., the
<template>block in a.vuefile or a template string), it traverses and parses the template's AST (Abstract Syntax Tree). - The compiler distinguishes between static and dynamic content within the template. Static content refers to parts that will never change when the component re-renders, such as a plain HTML tag
<div>or static text content "Hello". Dynamic content is bound to the component's reactive data, such as attributes bound viav-bind(:id="dynamicId"), text bound viav-textor double curly braces ({{ message }}), or dynamic structures controlled byv-if/v-for. - For identified dynamic nodes, the compiler does not simply mark them as "dynamic" as in Vue2 but further analyzes the type of dynamic binding for that node.
- When Vue3's compiler processes a template (e.g., the
-
Generating PatchFlag
- Based on the type of dynamic binding, the compiler generates a numeric flag, which is the PatchFlag. This number is essentially a bitmask, where each bit represents a specific type of change.
- Common PatchFlag types include:
TEXT = 1: Node has dynamic text content (e.g.,<div>{{ message }}</div>).CLASS = 2: Node has dynamic class binding (e.g.,<div :class="cls"></div>).STYLE = 4: Node has dynamic style binding (e.g.,<div :style="styl"></div>).PROPS = 8: Node has dynamic non-class/style attribute bindings (e.g.,<div :id="dynamicId"></div>).FULL_PROPS = 16: Node has dynamic attribute bindings whose specific types cannot be determined at compile time (e.g., when usingv-bind="object").HYDRATE_EVENTS = 32: Node has event listeners.STABLE_FRAGMENT = 64: A Fragment's structure order is stable.KEYED_FRAGMENT = 128: A Fragment's children have uniquekeys.UNKEYED_FRAGMENT = 256: A Fragment's children do not havekeys.NEED_PATCH = 512: A node only requires non-attribute patches, such as directive updates.
- If a node has multiple dynamic bindings, its PatchFlag is the result of a bitwise OR operation on these types. For example, a node with both dynamic text and dynamic class:
PatchFlag = TEXT | CLASS, resulting in1 | 2 = 3.
-
Efficient Runtime Diffing (Patching Process)
- When a component's reactive data changes and triggers a re-render, a new virtual DOM tree (VNode Tree) is generated.
- The renderer's
patchfunction is responsible for comparing the old and new VNode trees and updating the real DOM. This is known as "patching" or "diffing". - Key Optimization: When patching a node, the renderer checks whether the VNode has a
patchFlagproperty.- If
patchFlag === 0: Indicates a completely static node. In subsequent updates, the comparison process for this node and all its children can be skipped entirely, as its content will never change. - If
patchFlag > 0: Indicates a node with dynamic bindings. The renderer, based on the specific value ofpatchFlag, precisely knows which parts need updating.- For example, a node's
patchFlagisTEXT(value 1). During diffing, the renderer skips comparing this node's attributes, knowing only the text content might change. It only checks the.childrentext content of the old and new nodes and updates the real DOM'stextContentif they differ. - Another example: a node's
patchFlagisCLASS | STYLE(value 6). During diffing, the renderer skips comparing this node's children, knowing they are static. It only compares and updates the node'sclassandstyleattributes.
- For example, a node's
- If
Summary
The core idea of PatchFlag is "separation of static and dynamic content". Through "pre-analysis" during compilation, the dynamic parts of the template are marked and categorized. During runtime diffing, these flags are used to optimize the traditional "full comparison" into "targeted updates". In Vue3 applications, dynamic nodes typically constitute only a small portion, so this optimization can significantly reduce the computational load of virtual DOM diffing, especially in large component trees, leading to substantial performance improvements. This is a key reason why Vue3 outperforms Vue2 in terms of performance.