浅谈Vue 性能优化之深挖数组(3)

那么问题是不是出现在对 questions 进行 getter 的过程中,出现了 O(n³) 的复杂度呢?

于是,我打开了 Vue 的源码,由于之前深入研究过源码,所以轻车熟路地找到了 vue/src/core/instance/state.js 里面将 data 转换成 getter/setter 的部分。

function initData (vm: Component) {
 ......
 // observe data
 observe(data, true /* asRootData */)
}

定义一个组件的 data 的响应式,都是从 observe 函数开始,它的定义是位于 vue/src/core/observer/index.js

export function observe (value: any, asRootData: ?boolean): Observer | void {
 if (!isObject(value) || value instanceof VNode) {
  return
 }
 let ob: Observer | void
 if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
  ob = value.__ob__
 } else if (
  shouldObserve &&
  !isServerRendering() &&
  (Array.isArray(value) || isPlainObject(value)) &&
  Object.isExtensible(value) &&
  !value._isVue
 ) {
  ob = new Observer(value)
 }
 if (asRootData && ob) {
  ob.vmCount++
 }
 return ob
}

observe 函数接受对象或者数组,内部会实例化 Observer 类。

export class Observer {
 value: any;
 dep: Dep;
 vmCount: number;
 constructor (value: any) {
  this.value = value
  this.dep = new Dep()
  this.vmCount = 0
  def(value, '__ob__', this)
  if (Array.isArray(value)) {
   if (hasProto) {
    protoAugment(value, arrayMethods)
   } else {
    copyAugment(value, arrayMethods, arrayKeys)
   }
   this.observeArray(value)
  } else {
   this.walk(value)
  }
 }
 walk (obj: Object) {
  const keys = Object.keys(obj)
  for (let i = 0; i < keys.length; i++) {
   defineReactive(obj, keys[i])
  }
 }
 observeArray (items: Array<any>) {
  for (let i = 0, l = items.length; i < l; i++) {
   observe(items[i])
  }
 }
}

Observer 的构造函数很简单,就是声明了 dep、value 属性,并且将 value 的 _ ob _ 属性指向当前实例。举个栗子:

// 刚开始的 options 
export default {
  data : {
    msg: '消息',
    arr: [1],
    item: {
      text: '文本'
    }
  }
}
// 实例化 vm 的时候,变成了以下
data: {
  msg: '消息',
  arr: [1, __ob__: {
      value: ...,
      dep: new Dep(),
      vmCount: ...
    }],
  item: {
    text: '文本',
    __ob__: {
      value: ...,
      dep: new Dep(),
      vmCount: ...
    }
  },
  __ob__: {
    value: ...,
    dep: new Dep(),
    vmCount: ...
  }
}

也就是每个对象或者数组被 observe 之后,多了一个 _ ob _ 属性,它是 Observer 的实例。那么这么做的意义何在呢,稍后分析。

继续分析 Observer 构造函数的下面部分:

// 如果是数组,先篡改数组的一些方法(push,splice,shift等等),使其能够支持响应式
if (Array.isArray(value)) {
 if (hasProto) {
  protoAugment(value, arrayMethods)
 } else {
  copyAugment(value, arrayMethods, arrayKeys)
 }
 // 数组里面的元素还是数组或者对象,递归地调用 observe 函数,使其成为响应式数据
 this.observeArray(value)
} else {
 // 遍历对象,使其每个键值也能成为响应式数据  
 this.walk(value)
}
walk (obj: Object) {
  const keys = Object.keys(obj)
  for (let i = 0; i < keys.length; i++) {
   // 将对象的键值转换成 getter / setter,
   // getter 收集依赖
   // setter 通知 watcher 更新
   defineReactive(obj, keys[i])
  }
}
observeArray (items: Array<any>) {
  for (let i = 0, l = items.length; i < l; i++) {
   observe(items[i])
  }
}
      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/123.html