Vue生命周期与性能优化
生命周期
-
beforeCreate
在 Vue 实例初始化之后,数据观测(data observer)之前被调用; -
created
实例已创建完成之后被调用。在这一步,实例已完成这几个配置:数据观测、属性和方法的运算、watch/event 事件回调。这里还没有$el
; -
beforeMount
在挂在开始之前被调用,相关的 render 函数首次被调用; -
mounted
el
被创建的vm.$el
替换,并挂载到实例上去之后调用这个钩子; -
brforeUpdate
数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前; -
updated
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子; -
beforeDestory
实例销毁之前调用。在这一步,实例仍然完全可用; -
destroyed
Vue
实例销毁后调用,调用后,Vue
实例指示的所有东西都会接绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cfTn4DYi-1595644884459)(./img/lifecycle.png)]
各个生命周期内可以做的事情
-
created
实例已经创建完成,因为它是最早触发的原因,可以进行一些数据、资源的请求; -
mounted
实例已经挂载完成,可以进行一些 DOM 操作,也可以进行一些数据、资源的请求; -
beforeUpdate
可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程; -
updated
可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间,不被调用; -
beforeDestroy
可以执行一些优化操作,比如清空定时器,解除绑定事件。 -
beforeCreate 和 beforeMount,父组件会先触发;
-
创建 Vue 实例时(created),父组件会先创建。只有父组件先初始化,内部的子组件才会初始化;
-
挂载时(mounted),子组件先挂载。子组件渲染完了,父组件才会接着渲染完;
-
卸载时(beforeDestory),子组件先卸载。如果先卸载父组件,子组件如何处理?这可能会造成内层泄露;
-
beforeUpdate 父组件先触发更新;
-
updated 子组件先触发。子组件更新完了之后,父组件才算更新完成;
常见的性能优化
- 合理使用 v-show 和 v-if,更新不是很频繁时可以使用
v-if
,v-if 比较耗费性能,如果是频繁切换的场景就使用v-show
; - 合理使用 computed,计算属性会基于它们的响应式依赖进行缓存,只在相关响应式依赖发生改变时它们才会重新求值;
- v-for 时加上
key
,以及避免和 v-if 同时使用,因为 v-for 比 v-if 优先级更高,每次 v-for 时,v-if 都要重新计算一遍,这很浪费; - 自定义事件、DOM 事件、定时器等任务及时销毁(在 beforeDestory 中),避免内层泄露;
- 合理的使用异步组件,只在需要的时候才从服务器加载模块,而且 Vue 异步组件被渲染时会把结果缓存起来供未来重渲染;
- 合理的使用 keep-alive。对于不需要重新渲染的组件进行缓存,如多个静态 Tab 页的切换,可以用 keep-alive 包裹;
- data 层级不要太深,避免递归次数过多,消耗时间;
- 前端通用的性能优化,比如图片懒加载;
- 使用 SSR。
v-if 与 v-show
这两个指令都可以把元素隐藏或显示。当传入的数据是 true
是展示,false
会隐藏。不同的是:v-if
会把元素或者组件删掉(不渲染),即在 DOM 中移除;v-show
则会使用 CSS 当中的 display
属性,将其设置成 none
。可见,v-if
要比 v-show
性能低,尤其是在频繁切换的场景下。
key 的重要性
在循环中应使用 key
,且最好不要是 index
或者 random
。diff 算法中通过 tag 和 key 来判断是否是同一个节点(sameNode),使用 key
可以减少渲染次数,提高渲染性能。
Vuex
Vuex
是一个 Vue 状态管理库。与 Redux
相比,Vuex
理解起来要简单许多。它的大致工作流程如下:
图中绿色虚线部分就是 Vuex
的工作环境。