Vue编译网站:
Vue2.x:https://template-explorer.vuejs.org/#
Vue3.0:https://vue-next-template-explorer.netlify.app/#
PatchFlags:
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, // 静态节点
// 指示在 diff 过程应该要退出优化模式
BAIL = -2
}
Vue3.0六大亮点
- Performance:性能比Vue2.x快1.2~2倍
- Tree shaking support:按需编译,体积比Vue2.x更小
- Composition API:组合API(类似React Hooks)
- Custom Renderer API:暴露了自定义渲染API
- Fragment,Teleport(Protal),Suspense:更先进的组件
Vue3.0是如何变快的?
- diff 算法优化
- hoistStatic 静态提升
- cacheHandlers 事件监听缓存
- ssr 渲染
diff算法优化
- 在Vue2.x中的虚拟DOM是进行全量的对比
- Vue3.0新增了静态标记(PatchFlag),在与上次虚拟节点进行对比时候,只对比带有patch flag的节点,并且可以通过flag的信息得知当前节点要对比的具体内容
<div>
<p>hello</p>
<p>hello</p>
<p>hello</p>
<p>{
{msg}}}</p>
</div>
编译之后:
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("p", null, "hello"),
_createVNode("p", null, "hello"),
_createVNode("p", null, "hello"),
_createVNode("p", null, _toDisplayString(_ctx.msg) + "}", 1 /* TEXT */)
]))
}
hoistStatic静态提升
- Vue2.x中无论元素是否参与更新,每次都会重新创建,然后再渲染
- Vue3.0中对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可
<div>
<p>hello</p>
<p>hello</p>
<p>hello</p>
<p>{
{msg}}}</p>
</div>
没有静态提升时:
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("p", null, "hello"),
_createVNode("p", null, "hello"),
_createVNode("p", null, "hello"),
_createVNode("p", null, _toDisplayString(_ctx.msg) + "}", 1 /* TEXT */)
]))
}
静态提升之后:
const _hoisted_1 = /*#__PURE__*/_createVNode("p", null, "hello", -1 /* HOISTED */)
const _hoisted_2 = /*#__PURE__*/_createVNode("p", null, "hello", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createVNode("p", null, "hello", -1 /* HOISTED */)
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_hoisted_1,
_hoisted_2,
_hoisted_3,
_createVNode("p", null, _toDisplayString(_ctx.msg) + "}", 1 /* TEXT */)
]))
}
cacheHandlers事件监听缓存
默认情况下onClick会被视为动态绑定,所以每次都会去追踪它的变化。但是因为是同一个函数,所以没有追踪变化,可以直接缓存起来复用即可
<div>
<button @click="onClick">按钮</button>
</div>
没有开启事件监听缓存时:
转换之后的代码,可能还看不懂, 但是不要紧,我们只需要观察有没有静态标记即可。因为我们知道在Vue3.0的diff算法中,只有有静态标记的才会进行比较,才会进行追踪
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("button", {
onClick: _ctx.onClick }, "按钮", 8 /* PROPS */, ["onClick"])
]))
}
开启事件监听缓存之后:
export function render(_ctx, _cache, $props, $setup,