Data source in response to the principles of the Interpretation of

Foreword

By learning to understand Everest course Responsive principle Vue source.

Responsive principle

1. The core point: Object.defineProperty
2. Default Vue during initialization data using the attribute data will Object.defineProperty redefine all attributes, when the page corresponding to the acquired attribute. Collected will be dependent on (current collector assembly Watcher) If the property will notify dependency changed update operation.

What is dependent on the collection?
By Object.definePropertythe time to re-define data attributes, intercept, then the actual rendering; that before the actual rendering process series is dependent on the logical collection 上边有说,会在依赖收集的时候为每一个属性创建一个watcher,如果属性发生变化,则通知对应的 watcher 更新视图.

To look at the source
1, the first constructor initializes looks, src/core/instance/index.jsbecause we share the main principles of responsive data, that is, how the data is initialized Vue render and build listening, mainly to see stateMixin module
Here Insert Picture Description
2, into the stateMixinmodule, we look directly into the initDatafunction

function initData (vm: Component) { // 初始化data
  let data = vm.$options.data // 获取到用户传入的data数据
  data = vm._data = typeof data === 'function' // 模板语法与标准语法区分获取data数据
    ? getData(data, vm)
    : data || {}
  if (!isPlainObject(data)) { 
    data = {}
    process.env.NODE_ENV !== 'production' && warn(
      'data functions should return an object:\n' +
      'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
      vm
    )
  }
  // proxy data on instance
  const keys = Object.keys(data)
  const props = vm.$options.props
  const methods = vm.$options.methods
  let i = keys.length
  while (i--) {
    const key = keys[i]
    if (process.env.NODE_ENV !== 'production') {
      if (methods && hasOwn(methods, key)) {
        warn(
          `Method "${key}" has already been defined as a data property.`,
          vm
        )
      }
    }
    if (props && hasOwn(props, key)) {
      process.env.NODE_ENV !== 'production' && warn(
        `The data property "${key}" is already declared as a prop. ` +
        `Use prop default value instead.`,
        vm
      )
    } else if (!isReserved(key)) {
      proxy(vm, `_data`, key) // es6 proxy 代理
    }
  }
  /*
  中间我就跳过了,看意思是非生产环境下,对 props , methods 的一些定义,声明做的判断,不允许重复声明
  另外就是添加了 proxy , es6 新增代理属性 , 包含所有 Object.defineProperty 的功能, 重要的一点是解决 	了不能对象监听的问题等。
  */
  // observe data
  observe(data, true /* asRootData */) // 重点在这儿,为每一个data属性创建一个watcher
}

重点 : observe(data, true /* asRootData */) // 重点在这儿,为每一个data属性创建一个wathcer Next we went into the observer 类

3, src/core/observer/index.jsline 37
is below the Observer class, specifically it done, look at the code

export class Observer {
  value: any;
  dep: Dep;
  vmCount: number; // number of vms that have this object as root $data

  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 through all properties and convert them into
   * getter/setters. This method should only be called when
   * value type is Object.
   */
  walk (obj: Object) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) { // 遍历对象
      defineReactive(obj, keys[i]);  // 定义响应式数据,这里可以看到 defineReactive 方法
    }
  }

  /**
   * Observe a list of Array items.
   */
  observeArray (items: Array<any>) { // 遍历数组
    for (let i = 0, l = items.length; i < l; i++) {
      observe(items[i])  // 观测数组中的每一项 
    }
  }
}

By the code above, we see the main thing to do, is to distinguish between arrays and objects, and the data and objects traverse, create observer watcher=>defineReactive 方法

There will come on top when it comes to the array observeArraymethod, which is to traverse the call observer, some types of data and determine whether the monitor had not been listening to the callback go back to create an observation.

src/core/observer/index.js 113 line

export function observe (value: any, asRootData: ?boolean): Observer | void {
  if (!isObject(value) || value instanceof VNode) {
    /* 
    不是对象不进行观测,如:不管是模板语法还是标准语法data均是一个对象
    
    data () {   模板语法返回一个对象
      return  {}
    } 
    new Vue ({  标准语法 data 也是一个对象
      data:{}
    })
    */
    return
  }
  let ob: Observer | void
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { // 已经被监听的,不会重复监听
    ob = value.__b__
  } 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
}

If it is not an array, then go directly to defineReactiveMethod
src/core/observer/index.js148 lines defineReactive 响应式数据绑定关键方法where we use the word that is the Object.defineProperty () application; all initialization data will come here.

export function defineReactive (
  obj: Object,
  key: string,
  val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {
  const dep = new Dep()

  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  // cater for pre-defined getter/setters
  const getter = property && property.get
  const setter = property && property.set
  if ((!getter || setter) && arguments.length === 2) {
    val = obj[key]
  }

  let childOb = !shallow && observe(val) // 是数组则递归观测
  Object.defineProperty(obj, key, { // 重点
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () { // 数据的取值
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()  // 收集依赖 watcher
        if (childOb) {
          childOb.dep.depend()  // 收集依赖
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) { // 数据的设置值
      const value = getter ? getter.call(obj) : val
      /* eslint-disable no-self-compare */
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      /* eslint-enable no-self-compare */
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
      // #7981: for accessor properties without setter
      if (getter && !setter) return
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      dep.notify() // 触发数据对应的依赖进行更新 , 重点,重点,往下看
    }
  })
}

All collections observer Dep, which is a collection of wathcer, when creating the observed data is created for each attribute the watcherobserver ( Object.defineProperty方法的 get 里边), then the trigger data update setmethod calls dep.notify(), look at the code
src/core/observer/dep.js, line 13, Dep like to see saw constructor, add watcher, delete watcher and so on, then I think the point of view update methodnotify()

export default class Dep {
  static target: ?Watcher;
  id: number;
  subs: Array<Watcher>;

  constructor () {
    this.id = uid++
    this.subs = []
  }

  addSub (sub: Watcher) {
    this.subs.push(sub)
  }

  removeSub (sub: Watcher) {
    remove(this.subs, sub)
  }

  depend () {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }

  notify () { // 通知存储的依赖更新
    // stabilize the subscriber list first
    const subs = this.subs.slice()
    if (process.env.NODE_ENV !== 'production' && !config.async) {
      // subs aren't sorted in scheduler if not running async
      // we need to sort them now to make sure they fire in correct
      // order
      subs.sort((a, b) => a.id - b.id)
    }
    for (let i = 0, l = subs.length; i < l; i++) {
      subs[i].update() // 依赖中对应修改属性的update方法
    }
  }
}

update ()Methods src/core/observer/wachter.js166 rows, in fact, this is the definition of wachterthe observer class, inside various operation wachtermethods of the observer, such as: add, modify, remove the like.

to sum up

Well, the analysis here, in fact, has been very clear for data responsive principle, the overall process is:
Here Insert Picture Description

Published 21 original articles · won praise 40 · views 6071

Guess you like

Origin blog.csdn.net/HiSen_CSDN/article/details/104807792