1.vue3设计目标,做了哪些优化
更小
- 移除一些不常用的API
- tree-shaking,将无用模块剪辑,仅打包所需要的,使得打包的体积整体减小
更快
主要体现在编译阶段
- diff算法优化
- 静态提升
- 事件监听缓存
- SSR优化
更友好
- TypeScript支持
更好的类型检查 + 复杂类型推导 + 源码跳转 + 问题定位 + 调试便捷
- composition api
增强了代码逻辑组织和复用能力
2.vue3性能提升通过哪几个方面体现
编译阶段
vue2中的响应式系统,每一个组件实例对应一个watcher,它会在组件渲染的过程中把使用到的数据property记录为依赖,当依赖发生改变时候触发setter,则会通知watcher,从而使关联的组件重新渲染。
模版、动态节点、静态节点
- diff算法优化
1)预处理优化:
与vue2的双向遍历不一样,vue3首先会进行头尾的单项遍历,进行预处理优化
2)静态标记
vue2在patch阶段会进行全量diff,但是有的节点明明是不变的,没必要去diff,vue3中提出PatchFlags的概念,在可能变化的地方加一个flag标记,下次变化的时候直接找改地方进行比较
export const enum PatchFlags {
// 动态文本
TEXT = 1,
// 动态class
CLASS = 1 << 1,
// 动态style
STYLE = 1 << 2,
// 动态props
PROPS = 1 << 3,
// 动态变化的属性,比如:[attr] = "foo"
FULL_PROPS = 1 << 4,
...
}
- 静态提升
vue3中对于不参与更新的元素,会做静态提升,只会创建一次,在渲染时直接复用
对于模版
<span>你好</span>
<div>{{ message }}</div>
静态提升之前
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock(_Fragment, null, [
_createVNode("span", null, "你好"),
_createVNode("div", null, _toDisplayString(_ctx.message), 1 /* TEXT */)
], 64 /* STABLE_FRAGMENT */))
}
静态提升之后,静态内容在render函数之外,每次渲染取缓存中的进行复用即可,同时被打上了patchFlag,静态标记值是 -1
const _hoisted_1 = /*#__PURE__*/_createVNode("span", null, "你好", -1 /* HOISTED */)
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock(_Fragment, null, [
_hoisted_1,
_createVNode("div", null, _toDisplayString(_ctx.message), 1 /* TEXT */)
], 64 /* STABLE_FRAGMENT */))
}
- 事件监听缓存
默认情况下绑定事件行为会被视为动态绑定,所以每次都会去追踪它的变化
- SSR优化
当静态内容达到一定量级的时候,会使用createstaticVnode方法在客户端生成一个static node,这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染
源码体积减小
移除一些不需要的API + tree-shaking
composition api 中任何一个函数,仅仅在使用到才会被打包,没用到的模块都会被tree shaking
响应式系统
相比于vue2的Object.defineProperty方式对对象属性进行劫持带来的性能问题,以及数据属性的添加和删除无法做到响应式(提供了Vue.set和Vue.delete),vue3使用Proxy重写了响应式系统
3.为什么要使用Proxy代替defineProperty
defineProperty方式
function defineReactive(data, key, val){
const dep = new Dep()
Object.defineProperty(data, key, {
get(key){
if(Dep.target){
dep.depend
}
return val
},
set(key, newVal){
if(val !== newVal){
val = newVal
dep.notify()
}
}
}
}
proxy模式
function reactive(data){
const observed = new Proxy(obj, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
return isObject(res) ? reactive(res) : res
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver)
return res
},
deleteProperty(target, key) {
const res = Reflect.deleteProperty(target, key)
return res
}
})
}
弊端:
Proxy 不兼容IE,也没有 polyfill, defineProperty 能支持到IE9
我想这也是没有大面积开始使用vue3的原因吧
4.Options API 和 composition api 对比
- 逻辑组织和逻辑复用上,composition api 优于options api
- composition api 几乎都是函数,会有更好的类型推断
- composition api 对tree shaking更友好
- composition api 中没有this的使用,减少了this指向不明的问题
5.tree shaking原理
Tree shaking是基于ES6模板语法(import与exports),主要是借助ES6模块的静态编译思想,在编译时就能确定模块的依赖关系,以及输入和输出的变量
Tree shaking无非就是做了两件事:
编译阶段利用ES6 Module判断哪些模块已经加载 判断那些模块和变量未被使用或者引用,进而删除对应代码
参考
vue3源码:github.com/vuejs/vue-n…