Yesterday SAW uVU live broadcast, Vue3 core Typescript, Proxy responsive, Composition solution code repeatedly horizontal jump has a great article analysis, I summarize the virtual Dom part, and compare React, vDOM rewriting is also an important reason why Vue3 ‘performance is so good
- Understand Vue3 source code this one is enough
- What’s so great about Vue 3.0? (Comparison of update principles)
First of all, static markers can improve upADTE performance by 1.3~2 times and SSR performance by 2~3 times. How can this be done
Static tags for compiling templates
Let’s look at a very common piece of code
<div id="app">
<h1>Technology to touch the fish</h1>
<p>It's a nice day today</p>
<div>{{name}}</div>
</div>
Copy the code
This is resolved in VUe2
function render() {
with(this) {
return _c('div', {
attrs: {
"id": "app"
}
}, [_c('h1', [_v("Technology")]), _c('p', [_v("It's a beautiful day.")]), _c('div', [_v(
_s(name))])])
}
}
Copy the code
The first two tags are completely static and will not change in subsequent rendering. Vue2 still uses the _c newly built VDOM, which requires comparison during diff, resulting in some additional performance loss
Let’s take a look at the parsing results in VUe3
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("h1".null."Technology"),
_createVNode("p".null."It's a beautiful day."),
_createVNode("div".null, _toDisplayString(_ctx.name), 1 /* TEXT */)))}// Check the console for the AST
Copy the code
The final _createVNode and the fourth parameter, 1, are tracked only when they are used. Static nodes do not need to be traversed. This is the main source of vue3’s excellent performance
<div id="app">
<h1>Technology to touch the fish</h1>
<p>It's a nice day today</p>
<div>{{name}}</div>
<div :class="{red:isRed}">Fishing in character</div>
<button @click="handleClick">Poking me</button>
<input type="text" v-model="name">
</div>
Copy the code
Preview the results of parsing online
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("h1".null."Technology"),
_createVNode("p".null."It's a beautiful day."),
_createVNode("div".null, _toDisplayString(_ctx.name), 1 /* TEXT */),
_createVNode("div", {
class: {red:_ctx.isRed}
}, "Touch fish symbol".2 /* CLASS */),
_createVNode("button", { onClick: _ctx.handleClick }, "Poking me".8 /* PROPS */["onClick"]]))}// Check the console for the AST
Copy the code
_createVNode () < div style = “border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none; border-box: none Take a look at the notes that dissuade the big brothers
export const enum PatchFlags {
TEXT = 1.// Represents an element with a dynamic textContent
CLASS = 1 << 1.// represents an element with a dynamic Class
STYLE = 1 << 2.// static (e.g. Style ="color: red")
PROPS = 1 << 3.// represents an element with non-class/style dynamic items.
FULL_PROPS = 1 << 4.// Represents the element of an item with a dynamic key, which is incompatible with the above three
HYDRATE_EVENTS = 1 << 5.// Represents an element with an event listener
STABLE_FRAGMENT = 1 << 6.// indicates a fragment whose child order is invariant.
KEYED_FRAGMENT = 1 << 7.// represents a fragment with keyed or partially keyed child elements.
UNKEYED_FRAGMENT = 1 << 8.// represents a fragment with a keyless binding
NEED_PATCH = 1 << 9.// Indicates that only elements that are not attribute patches are required, such as ref or hooks
DYNAMIC_SLOTS = 1 << 10.// represents an element with a dynamic slot
}
Copy the code
If we have both props and text bindings, we can use a bit-operation combination
<div id="app">
<h1>Technology to touch the fish</h1>
<p>It's a nice day today</p>
<div :id="userid"">{{name}}</div>
</div>
Copy the code
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("h1".null."Technology"),
_createVNode("p".null."It's a beautiful day."),
_createVNode("div", {
id: _ctx.userid,
"\" ": ""
}, _toDisplayString(_ctx.name), 9 /* TEXT, PROPS */["id"]]))}// Check the console for the AST
Copy the code
Text is 1, and props is 8, and when combined, it is 9. We can simply use bit operations to determine whether the text and props need to be compared
code
export const PLUGIN_EVENT_SYSTEM = 1;
export const RESPONDER_EVENT_SYSTEM = 1 << 1;
export const USE_EVENT_SYSTEM = 1 << 2;
export const IS_TARGET_PHASE_ONLY = 1 << 3;
export const IS_PASSIVE = 1 << 4;
export const PASSIVE_NOT_SUPPORTED = 1 << 5;
export const IS_REPLAYED = 1 << 6;
export const IS_FIRST_ANCESTOR = 1 << 7;
export const LEGACY_FB_SUPPORT = 1 << 8;
Copy the code
Event caching
The binding @click will be stored in the cache link
<div id="app">
<button @click="handleClick">Poking me</button>
</div>
Copy the code
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("button", {
onClick: _cache[1] || (_cache[1] = $event= > (_ctx.handleClick($event)))
}, "Poking me")))}Copy the code
The incoming event automatically generates and caches an inline function and becomes a static node in the cache. This way, even if we write our own inline functions, it won’t cause unnecessary duplicate rendering
Static ascension
code
<div id="app">
<h1>Technology to touch the fish</h1>
<p>It's a nice day today</p>
<div>{{name}}</div>
<div :class="{red:isRed}">Fishing in character</div>
</div>
Copy the code
const _hoisted_1 = { id: "app" }
const _hoisted_2 = _createVNode("h1".null."Technology".- 1 /* HOISTED */)
const _hoisted_3 = _createVNode("p".null."It's a beautiful day.".- 1 /* HOISTED */)
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", _hoisted_1, [
_hoisted_2,
_hoisted_3,
_createVNode("div".null, _toDisplayString(_ctx.name), 1 /* TEXT */),
_createVNode("div", {
class: {red:_ctx.isRed}
}, "Touch fish symbol".2 /* CLASS */)))}Copy the code
Vdom for VUE3 and React Fiber
Many people joke that React is becoming more and more like the API, which represents the two directions of the front end
Vue1.x
There is no VDOM, completely responsive, each data change, through the responsive notification mechanism to new Watcher work, just like when the independent group was small, each soldier enlisted and promoted, all take the initiative to inform our old Li, convenient management
As the project grows in size, too many Watchers can lead to performance bottlenecks
React15x
In the era of Act15, there was no responsiveness, the data changed, the whole new data and the old data diff, calculate the difference, then you know how to modify the DOM, just like the command room of Lao Li had a model, every personnel change, by comparing all the differences, you know the change, it seems that there is a lot of calculation. But this IMmutable data structure is more friendly to large projects, and after the success of Vdom abstraction, it is possible to switch to other platform render, whether playing the Devils or playing the national army, using a Vdom mode
The same problem is that if dom nodes continue to multiply and each diff takes longer than 16ms, it can cause stuttering (60fps).
Vue2.x
The introduction of VDOM, control the granularity, component level to go through the Watcher notification, components inside the VDOM to do diff, neither too much watcher, also will not let the size of the VDOM is too large, the diFF over 16ms, is really excellent ah, just like the independent regiment after large, only the battalion commander level changes, will notify Li. Internal diff managed by itself
React 16 Fiber
React goes the other way. Since the main problem is that diff causes a lag, React goes the other way, using CPU scheduling logic to make the vdom tree into a linked list, using the browser’s idle time to do diff. If it is longer than 16ms and there is an animation or user interaction task, the main process control is returned to the browser. Idle to continue, especially like waiting for the goddess’s spare tire
The diff logic becomes a one-way linked list, and whenever the main thread goddess is free, we’re just going to continue to get up and do diff, and if you look at requestIdleCallback, that’s what it looks like from a browser point of view
About the code
requestIdelCallback(myNonEssentialWork);
// Wait for the goddess to be free
function myNonEssentialWork (deadline) {
// deadline.timeremaining ()>0
// There are diff missions left unplayed
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
doWorkIfNeeded();
}
// Goddess is out of time, return goddess 🤣
if (tasks.length > 0){ requestIdleCallback(myNonEssentialWork); }}Copy the code
Vue3
ShouldComponentUpdate shouldComponentUpdate should change the default component to Pure or Memo. This is not the only way to implement static markup and event caching. Maybe this is life
React gives you freedom, while Vue makes you last, which is probably why both Vue and React are so popular in China
Vue3 uses Proxy responsiveness + component internal VDOM + static markup to control the granularity of the task sufficiently that time-slice is not necessary
In life, kids study the pros and cons every day, adults choose me, and I look forward to the new features of Act17
Live details
At the end of the q&A period, I couldn’t avoid the problem of hair volume, unfortunately, I didn’t recommend any hair conditioner. I looked at it carefully, it seems that after vuE3 was released, you really improved your hairline. I wish you can have black hair while improving your technology