文章开始之前我先备注下本篇文章需要使用到的工具网站,他们的作用是把模板生成render函数
Vue Template Explorer
vue2:https://vue-template-explorer.netlify.app/
vue3:https://vue-next-template-explorer.netlify.app/
1)静态标记(patchFlag)
Vue2中的虚拟dom是进行全量对比的
Vue3新增了静态标记(PatchFlag),在与上次数据虚拟节点对比的时候只对比有patchFlag的节点,并且可以通过静态标记得到本次要对比的内容
可以在Vue3 Template Explorer中得到验证
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 */)
]))
}
很明显我们可以看见生成的render函数中有一个标记1,至于1代码什么意思我们可以查看VUE3的源码
目录为:vue-next-master/packages/shared/src/patchFlags.ts
export const enum PatchFlags {
TEXT = 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 或部分子节点有key
UNKEYED_FRAGMENT = 1 << 8,//256 子节点没有key的 fragment
NEED_PATCH = 1 << 9,//512 一个节点只会进行非props比较
DYNAMIC_SLOTS = 1 << 10,//1024 动态slot
HOISTED = -1,//静态节点
BAIL = -2//指示在diff过程应该要退出优化模式
}
2)静态提升(hoistStatic)
vue2中无论元素是否参与更新,都会被重新创建
vue3中不需要参与更新的dom只会被创建一次并缓存,之后每一次都使用缓存即可
<!--测试模板-->
<div>
<p>这是一个段落</p>
<p>{{msg}}</p>
</div>
可以根据vue通过模板生成render函数的网站来进行测试
//vue3 Template Explorer默认不勾选右上角options的hoistStatic时
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 Template Explorer勾选右上角options的hoistStatic时
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 */)
]))
}
很明显,勾选右上角options的hoistStatic之后,将不用更新的dom缓存成了一个全局变量hoisted,之后render函数的每一次执行都不会再创建这个dom
3)事件侦听缓存(cacheHandles)
默认情况下时间侦听被视为动态绑定,所以每次都会追踪他的变化,但是因为为同一函数,所以没有必要追踪变化,直接缓存起来复用即可
同样的我们还是在vue3 Template Explorer中来测试一下
<!--测试模板-->
<div>
<p @click="onClick"></p>
</div>
//vue3 Template Explorer默认不勾选cacheHandlers时生成的render函数
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("p", { onClick: _ctx.onClick }, null, 8 /* PROPS */, ["onClick"])
]))
}
//vue3 Template Explorer勾选cacheHandlers之后生成的render函数
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("p", {
onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick && _ctx.onClick(...args)))
})
]))
}
结果依然明显,勾选cacheHandlers之后,创建的p节点上面少了一个8的标记
4)服务端渲染的优化
1,当有大量静态内容的时候,这些内容会被当做纯字符串推进一个buffer里面,即使存在动态的绑定,会通过模板插值嵌入进去,这样会比虚拟DOM来渲染快上很多很多
2,当静态内容大到一定量级的时候,会通过_createStaticVNode方法在客户端生成一个static node,这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。
那么这一章我们主要以Vue Template Explorer生成render函数的方式来讲了下一vue3的三个新特性patchFlag,hoistStatic,cacheHandles即静态标记,静态提升,事件侦听缓存,以及描述了下服务端渲染的优化