一、静态提升
1、针对于静态节点,没有绑定动态内容
例如<h1>你好<h1/>,这种属于永久不变的静态节点,vue2的处理方式如下
// vue2的静态节点
render() {
createVNode("h1", null, '你好')
}
这种处理方式,每次渲染时都会新建一个节点
vue3的处理方式如下,用一个变量接收创建的节点,每次渲染时调用这个变量即可,这样节点 就只会创建一次
//vue3的静态节点
const hoisted = createVNode("h1", null, "你好")
function render() {
// 直接调用hoisted即可
}
2、针对于动态绑定内容,但是静态属性的情况,静态属性会被提升
<div class="user">
{{user.name}}
</div>
vue3的处理方式是将静态属性用变量接收,每次创建动态节点时,调用变量
const hoisted = { class: "user" }
function render(){
createVNode("div", hoisted, user.name)
}
二、预字符串化
<div class="menu-bar-container">
<div class="logo">
<h1>logo</h1>
</div>
<ul class="nav">
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
</ul>
<div class="user">
<span>{{ user.name }}</span>
</div>
</div>
当编译器遇到大量连续的静态内容,会直接将其编译为一个普通字符串节点
注:预字符串化只针对于连续出现的大量的静态节点,一般为超过20个的连续静态节点
三、缓存事件处理函数
在调用render函数时,会调用cache缓存,判断cache[0]是否存在,存在即调用,不存在即赋值调用
<button @click="count++">plus</button>
// vue2的处理方式
render(ctx){
return createVNode("button", {
onClick: function($event){
ctx.count++;
}
})
}
// vue3的处理方式
render(ctx, _cache){
return createVNode("button", {
onClick: cache[0] || (cache[0] = ($event) => (ctx.count++))
})
}
四、Block Tree
vue2在对比新旧树的时候,并不知道哪些节点是静态的,哪些是动态的,因此只能一层一层比较,这就浪费了大部分时间在比对静态节点上
五、PatchFlag(静态标记)
在vue2中,每次更新diff,都是全量对比,Vue3则只对比带有标记的,这样大大减少了非动态内容的对比消耗
<div class="user" :class="user.name">
<span :class="user.name">{{ user.name }}</span>
</div>
TEXT = 1, // 1 文本节点
CLASS = 1 << 1, // 2 class
STYLE = 1 << 2, // 4 style
PROPS = 1 << 3, // 8 属性,不包括类名和样式
FULL_PROPS = 1 << 4, // 16 key,当 key 变化时需要完整的 diff 算法做比较
HYDRATE_EVENTS = 1 << 5, // 32 表示带有事件监听器的节点
STABLE_FRAGMENT = 1 << 6, // 64 一个不会改变子节点顺序的 Fragment
KEYED_FRAGMENT = 1 << 7, // 128 带有 key 属性的 Fragment
UNKEYED_FRAGMENT = 1 << 8, // 256 子节点没有 key 的 Fragment
NEED_PATCH = 1 << 9, // 512 表示只需要non-props修补的元素 (non-props不知道怎么翻才恰当~)
DYNAMIC_SLOTS = 1 << 10, // 1024 动态的solt
DEV_ROOT_FRAGMENT = 1 << 11, //2048 表示仅因为用户在模板的根级别放置注释而创建的片段。 这是一个仅用于开发的标志,因为注释在生产中被剥离。
//以下两个是特殊标记
HOISTED = -1, // 已提升的静态vnode,更新时调过整个子树
BAIL = -2 // 差异算法应该退出优化模式
注:1<<n 表示十六进制中 1向左移n位, 如: 1<<3 ,则表示 0001 变成 0100 即:8