Vue
diff 过程简单理解
- 每次
vnode都是执行同级比对,不会跨级比较 - 快速判断,
isSameVnodeType函数会判断两个节点是否相同,主要判断type、key是否相同 - 使用
isSameVnodeType函数从头到尾快速判断进行更新,直到遇到不同节点 - 使用
isSameVnodeType函数从尾到头快速判断进行更新,直到遇到不同节点 - 新、旧节点之间多余节点的对比更新,进行新增或删除
- 乱序节点,使用最长递增子序列进行查找,涉及新增、删除、移动、打补丁等节点操作
vue3对diff过程的优化在于,添加了区分静态类型vnode,如果是 静态类型 的vnode,则跳过更新,直接修改旧vnode引用 指向新的vnode。
vue 中的事件触发器 vei (vue event invoke)
addEventListener 和 removeEventListener 事件的频繁注册、销毁必定会消耗大量内存时间,故 vue 中使用 vei 来做事件的注册销毁,简单来说就是动态修改事件回调函数,即 invoke.value , 简易示例如下代码
js
// invoke,实际执行的是 invoke.value ,修改事件代码只需重新赋值 invoke.value 即可
var invoke = () => {
invoke.value()
}
// 事件挂载
invoke.value = () => {
console.log('事件1执行')
}
// 注册一次 click 事件即可
el.addEventListener('click', invoke)
// 事件重新挂载,而不用重新 removeEventListener 后再 addEventListener
invoke.value = () => {
console.log('事件2执行')
}vue3 中 ref、toRef、toRefs 区别
ref用于定义 简单值类型 的 具有响应式 的数据。也常用于定义数组类型。toRef用于对reactive类型数据 的 某个属性 新创建一个reftoRefs用于对reactive类型数据 所有属性 创建ref,返回一个普通对象
watch 和 watchEffect 区别
watch需要指定监听某个值,传入ref或 函数(函数应返回要监听的属性)或数组watchEffect则不用指定监听值,立即执行传入的一个函数,会自动收集要监听的数据,在数据改变时自动执行;初始化时会执行一次,收集需要监听的数据
vue3 升级特性
createAppemits属性- 生命周期
- 移除
.sync,改为v-model - 移除
filter - 移除
$on、$off、$once实例方法 - 异步加载组件, 由
import增加defineAsyncComponent - 多事件, 可同时绑定多个事件,逗号连接
- 新增
v-memo指令优化数据渲染 Composition APIreactiverefreadonlywatch、watchEffectsetup- 生命周期钩子函数,
setup代替创建钩子,命名on+ 钩子函数名
TeleportSuspenseFragment
Proxy 实现响应式的性能提升
Proxy初始化时只监听了浅层属性,只有使用到深层属性才进行监听;而Object.defineProperty初始化时递归将属性转为响应式- 可监听 新增/删除 属性
- 可监听数组变化
Proxy 能规避 Object.defineProperty 的问题,但无法兼容 ie,无法 polyfill
vue3 比 vue2 快
Proxy响应式- 响应式数据的惰性监听,只监听初始渲染的可见部分的数据,惰性监听
PatchFlag标记- 编译模板时,标记动态节点,并区分
text、props等 diff算法优化 区分静态节点,以及不同类型的动态节点,diff过程中跳过静态节点的比对
- 编译模板时,标记动态节点,并区分
hoistStatic静态提升- 将静态节点的定义,提升静态节点到父作用域,缓存起来
- 多个相邻的静态节点,会被合并静态节点,并提升到父作用域缓存起来
- 空间换时间的优化策略
cacheHandler事件缓存- 缓存事件,事件函数一般不会变
- 支持多事件,使用逗号隔开
SSR优化- 静态节点直接输出,绕过 vdom
tree-shaking- 根据
ES6的 (importexports),ES6 module为静态导入,故能在编译阶段就能知道哪些模块使用了 - 另外说一下
CommonJs是支持动态导入(js执行时导入),但是动态导入就没法在编译阶段做tree-shaking
- 根据
typescript更好的支持
nextTick 在 vue2 和 vue3 中的实现区别
vue2中为了兼容性,使用了几个异步api来实现PromiseMutationObserversetImmediatesetTimeout
vue3中则不考虑兼容性,直接使用了Promise来实现tsexport function nextTick(fn?: () => void): Promise<void> { return fn ? p.then(fn) : p }
为何使用 Proxy 代替 Object.defineProperty
Object.defineProperty检测不到对象属性的添加和删除;Proxy能监听整个对象多达13种操作。Object.defineProperty无法监听数组;Proxy可以。Object.defineProperty需要对每个属性进行递归监听;Proxy可以惰性监听。
vite 为何启动快
- 开发环境 使用
es6 module特性 与esbuild等,无需打包,非常快 - 生产环境 使用
rollup, 配合esbuild进行编译、压缩等操作
由此 vite 的缺点也很明显,就是开发环境、生产环境不统一 导致的某些问题较难排查。且目前生态不及 webpack , 但这些问题都随着更新而抹平
单页应用首屏加载速度慢可能原因
可能原因
- 网络延迟
- 资源文件体积大小
- 脚本执行时间过长
解决方法
- 减小入口文件体积
- 路由懒加载,已函数形式加载路由
Tree-shaking去除未使用的代码
- 静态资源本地缓存
- 采用
http缓存,后端返回资源设置Expire、Cache-control、Last-Modified、Etag等 - 前端合理利用
localStorage
- 采用
ui框架按需加载、 框架资源使用CDN- 图片压缩、懒加载
- 开启
GZip压缩
组件和插件区别
- 编写形式
- 组件编写:
.vue文件或.jsx、.tsx文件 - 插件编写:包含
install方法的对象
- 组件编写:
- 注册方式
- 组件
Vue.component() - 插件
Vue.use()
- 组件
- 使用场景
- 组件用来构成
App业务模块 - 插件用来增强
Vue功能
- 组件用来构成