简介

vue函数式组件大部分人在开发过程中用到的不多,就连官网文档地位搁置的也比拟费解,然而在咱们对我的项目做性能优化时,却是一个不错的抉择。本文将对函数式组件初始化过程做一个系统性的论述,通过本文,你将理解到以下内容:

  • 什么是函数式组件
  • 函数式组件与一般组件间的差别
  • vue类似性能优化点

什么是函数式组件

函数式组件即无状态组件,没有datacomputedwatch,也没有生命周期办法,组件中也没有this上下文,只有props传参。在开发中,有很多组件仅仅只用到了props和插槽,这部分组件就能够提炼为函数式组件。借用官网demo,最简略的函数式组件如下:

Vue.component('my-component', {  functional: true,  // Props 是可选的  props: {    // ...  },  // 为了补救短少的实例  // 提供第二个参数作为上下文  render: function (createElement, context) {    // ...  }})

函数式组件与一般组件间的差别

组件实例化过程大抵分为四步,状态初始化 --> 模板编译 --> 生成VNode --> 转换为实在DOM。接下来比照一般组件与函数式组件罕用配置项,比拟下差别。

性能点名称一般组件函数式组件形容
vmYN组件作用域
hooksYN生命周期钩子
dataYN数据对象申明
computedYN计算属性
watchYN侦听器
propsYY属性
childrenYYVNode 子节点的数组
slotsYY一个函数,返回了蕴含所有插槽的对象
scopedSlotsYY作用域插槽的对象
injectionsYY依赖注入
listenersYY事件监听
parentYY对父组件的援用

从上表中能够看出,一般组件与函数式组件最大的差异在于函数式组件没有独立作用域,没有响应式数据申明。没有独立作用域,会有以下长处:

  1. 没有组件实例化(new vnode.componentOptions.Ctor(options)),函数式组件获取VNode仅仅是一般函数调用

    • 无公共属性、办法拷贝
    • 无生命周期钩子调用
  2. 函数式组件间接挂载到父组件中,缩短首次渲染、diff更新门路

    • 函数式组件在父组件生成VNode时,函数式组件render办法会被调用,生成VNode挂载到父组件children中,patch阶段可间接转换成真是DOM,一般组件则在createElm时,走组件初始化流程。
    • diff更新时,函数式组件调用render,间接创立一般VNode,而一般组件创立的VNode的是蕴含组件作用域的,diff操作时,还有额定调用updateChildComponent更新属性、自定义事件等,调用链路会比拟长。

vue性能优化点

函数式组件带来的性能晋升次要体现在缩短渲染门路缩小组件嵌套层级,前者与浏览器重绘回流有殊途同归之处,后者能够升高工夫复杂度。

无论何种性能优化,能从代码层面做优化的,无疑是代价最小的,尽管有时成果不是很显著,然而千里之行;始于足下。在vue中,有不少与上述类似的点,能够晋升代码执行效率。

正当申明data中数据,确保data中申明数据都是必须的

很多时候有一些数据没必要申明在data中,比方须要组件内共享,但不须要响应式解决的数据。data中的数据,对象都会对其深度优先用Object.defineProperty申明,数组也会拦挡基本操作办法。不必要的申明会造成无意义的数据劫持

正当应用computedwatch

computedwatch最大的区别在于computed是惰性加载的。惰性加载次要体现在两个方面:

  1. 依赖状态产生扭转时,不会立刻触发,只是扭转以后Watcher实例的dirty属性值为true
  2. 当对计算属性值取操作时,当且仅当watcher.dirty === true时,才会触发计算

以上两点个性,可能防止一些不必要的代码执行,具体代码如下所示:

// src\core\instance\state.jsfunction createComputedGetter (key) {  return function computedGetter () {    // 获取实例上的computed属性的watcher实例    const watcher = this._computedWatchers && this._computedWatchers[key]    if (watcher) {      // 当且仅当computed依赖属性发生变化 && 对计算属性进行取操作,才会调用Watcher的update办法,将dirty置为true      if (watcher.dirty) {        // 调用get办法,获取到computed的值        watcher.evaluate()      }      if (Dep.target) {        watcher.depend()      }      return watcher.value    }  }}// src\core\observer\watcher.jsupdate () {  // computed watcher lazy === true  if (this.lazy) {    // 标记懒执行是否可执行状态,false不执行计算属性计算    this.dirty = true  } else if (this.sync) { // 同步执行    this.run()  } else {    // 将以后watcher放入到watcher队列    queueWatcher(this)  }}

v-for绑定key值

v-for循环定义key值目标是便于精准找到diff比对节点,防止一些无意义的比对。

一般diff: 从头尾开始,新旧节点头尾别离比拟,游标向两头聚拢,当且仅当一个节点遍历完结后,diff流程完结

带有key值diff: 依据key值保护一个hash表,每次循环精准定位到更新指标节点,当且仅当一个节点遍历完结后,diff流程完结

思考

vue中,很多性能优化点都是缩短代码执行门路,尤其在存在大量计算逻辑中,性能的晋升会有肉眼可见的成果。理论开发中,也有不少场景能够用到此类优化办法,举个最简略的例子,关键词高亮匹配。实现这个操作,须要以下几步:

  1. 获取匹配关键词,将关键词进行格式化(对正则表达式中有意义的字符串进行本义)
  2. 动静生成匹配的正则表达式
  3. 依据正则表达式进行replace操作

有些时候,第一, 二步咱们能够省略,间接执行第三步即可,因为输出关键字可能存在雷同的,因而咱们能够将字符串与正则表达式缓存在Map中,下次匹配时,如果存在缓存,间接从缓存中拿即可。

vue模板编译用到的就是这个个性,每次会把编译的模板字符串作为key值,render办法作为value,缓存起来,如果遇到一样的模板,能够省去编译流程,带来肯定的性能晋升。

小结

养成良好的编码习惯,对于集体能力,也是一个不错的晋升。