Vue3.0快在哪儿?
一.diff算法的优化
**vue2:**数据发生变化之后是生成一棵新的DOM树,然后就行全局对比。
如下图:
**vue3:**新增静态标记(Patch flag)在与上次的虚拟节点进行对比,只对比带有Patch flag的节点并且可以通过flag的信息得知当前节点要对比的具体内容
如图:
附录Patch Flags
export const enum PatchFlags {
TEXT = 1,//动态文本节点
CLASS = 1 << 1,//动态class
STYLE = 1 << 2,//动态style
PROPS = 1 << 3,//动态属性
FULL_PROPS = 1 << 4,//具有动态key属性
HYDRATE_EVENTS = 1 << 5,//带有监听事件的节点
STABLE_FRAGMENT = 1 << 6, //一个不会改变子节点顺序的fragment
KEYED_FRAGMENT = 1 << 7, //带有key属性的fragment或者部分子字节有key
UNKEYED_FRAGMENT = 1 << 8, //子节点没有key的fragment
NEED_PATCH = 1 << 9, //一个节点只会进行非props比较
DYNAMIC_SLOTS = 1 << 10, //动态插槽
HOISTED = -1, //静态节点
BAIL = -2 //提示在diff过程应该退出优化模式
}
二.静态提升(hoist static)
**Vue2:**中无论元素是否参与更新,每次都会重新创建,然后再渲染
**Vue3:**中对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可
demo
<div>
<p>我是段落</p>
<p>{
{msg}}</p>
</div>
vue2.0静态提升前
import {
createVNode as _createVNode,
toDisplayString as _toDisplayString,
openBlock as _openBlock,
createBlock as _createBlock
} from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("p", null, "我是段落"),
_createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)
]))
}
vue3.0静态提升后
import {
createVNode as _createVNode,
toDisplayString as _toDisplayString,
openBlock as _openBlock,
createBlock as _createBlock
} from "vue"
//生成静态节点
const _hoisted_1 = /*#__PURE__*/_createVNode("p", null, "我是段落", -1 /* HOISTED */)
//动态节点
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_hoisted_1,//静态节点复用
_createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)
]))
}
三.事件侦听器缓存(cache handlers)
默认情况下onClick会被视为动态绑定,所以每次都会去追踪它的变化但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可
demo
<div>
<button @click="onClick">按钮</button>
</div>
vue2.0缓存之前
import {
createVNode as _createVNode,
openBlock as _openBlock,
createBlock as _createBlock
} from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("button", {
onClick: _ctx.onClick }, "按钮", 8 /* PROPS */, ["onClick"])
]))//UNKEYED_FRAGMENT = 1 << 8:有静态标记当做动态属性每次更新进行对比
}
vue3.0缓存之后
import {
createVNode as _createVNode,
openBlock as _openBlock,
createBlock as _createBlock
} from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("button", {
onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick(...args)))
}, "按钮")
]))//没有了静态标记不会更新后在进行对比
}
**注意点:**转换之后的代码,大家可能还看不懂,但是不要紧,我们只需要观察有没有静态标记即可,因为我们知道在Vue3的diff算法中,只有有静态标记的才会进行比较,才会进行追踪
四.ssr渲染(服务器端渲染)
-
当有大量静态内容时候,这些内容会被当做纯字符串推进一个buffer里面,即使存在动态绑定,会通过模板插值嵌入进去。这样会比通过虚拟dom来渲染的快上很多很多。
-
当静态内容大到一定量级时候,会用_createStaticVNode方法在客户端生成一个static node,这些静态node,会被直接innerHTML,就不需要创建对象,然后根据对象渲染。