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

我们再捋一下思路,首先在 initState 里面调用 initData,initData 得到用户配置的 data 对象后调用了 observe,observe 函数里面会实例化 Observer 类,在其构造函数里面,首先将对象的 _ ob _ 属性指向 Observer 实例(这一步是为了检测到对象添加或者删除属性之后,能触发响应式的伏笔),之后遍历当前对象的键值,调用 defineReactive 去转换成 getter / setter。

所以,来分析下 defineReactive。

// 如果是数组,先篡改数组的一些方法(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])
  }
}

首先,我们从 defineReactive 可以看出,每个响应式属性都有一个 Dep 实例,这个是用来收集 watcher 的。由于 getter 与 setter 都是函数,并且引用了 dep,所以形成了闭包,dep 一直存在于内存当中。因此,假如在渲染组件的时候,如果使用了响应式属性 a,就会走到上述的语句1,dep 实例就会收集组件这个 renderWatcher,因为在对 a 进行 setter 赋值操作的时候,会调用 dep.notify() 去 通知 renderWatcher 去更新,进而触发响应式数据收集新一轮的 watcher。

那么语句2与3,到底是什么作用呢

我们举个栗子分析

<div>{{person}}<div>
export default {
 data () {
  return {
   person: {
    name: '张三',
    age: 18
   }    
  }
 }
}

this.person.gender = '男' // 组件视图不会更新

因为 Vue 是无法探测到对象增添属性,所以也没有一个时机去触发 renderWatcher 的更新。

为此, Vue 提供了一个 API, this.$set ,它是 Vue.set 的别名。

export function set (target: Array<any> | Object, key: any, val: any): any {
 if (Array.isArray(target) && isValidArrayIndex(key)) {
  target.length = Math.max(target.length, key)
  target.splice(key, 1, val)
  return val
 }
 if (key in target && !(key in Object.prototype)) {
  target[key] = val
  return val
 }
 const ob = (target: any).__ob__
 if (target._isVue || (ob && ob.vmCount)) {
  process.env.NODE_ENV !== 'production' && warn(
   'Avoid adding reactive properties to a Vue instance or its root $data ' +
   'at runtime - declare it upfront in the data option.'
  )
  return val
 }
 if (!ob) {
  target[key] = val
  return val
 }
 defineReactive(ob.value, key, val)
 ob.dep.notify()
 return val
}
      

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

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