Observer source parsing

Foreword

In the Observer source section has three main roles: Observer, Dep, Watcher.

Observer

See this section, you can view with the following questions:

1, it can be what conditions become responsive to

2, Observer is how to deal with each incoming array or object?

3, there are two new Dep, what role they are?

4, the core code defineReactive what did?

5. What Dep.target that? When defineReactive in get, why should judge Dep.target?

  • Under what conditions may be responsive to become
function observe (value, asRootData) {
  if (!isObject(value) || value instanceof VNode) {
    return
  }
  let ob
  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
}
复制代码

In fact, there are a lot of judgment in the above code, we can draw the following conclusions:

(1) must be an object, and can not be vnode type.

  • Observer is how to handle incoming array or object, respectively
if (Array.isArray(value)) {
  if (hasProto) {
    protoAugment(value, arrayMethods)
  } else {
    copyAugment(value, arrayMethods, arrayKeys)
  }
  this.observeArray(value)
} else {
  this.walk(value)
}
复制代码

This code is to determine the value passed is not an array, if it is an array, go observeArray method, if not an array, then go walk method.

walk (obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i])
    }
}
observeArray (items) {
    for (let i = 0, l = items.length; i < l; i++) {
      observe(items[i])
    }
}
复制代码

The walk is to traverse the object, and the object attribute value to become responsive after the traverse end, the entire object is in response to the Object. This method is observeArray iterate, then each element in the array responsive flow down again.

  • There are two new Dep, what role are

First place:

class Observer {
  constructor (value) {
    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)
    }
  }
复制代码

Second place:

function defineReactive (
  obj,
  key,
  val,
  customSetter,
  shallow
) {
  const dep = new Dep()
  // 省略中间代码
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        // 省略中间代码
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      // 省略中间代码
      dep.notify()
    }
  })
}
复制代码

Second place dep We well understood, is to get and set service dependency collect and distribute updates.

At first dep, we can consider that he is a property of the entire object, then he when to rely on the collection and distribution of updates.

We can search about global dep.depend. We will find the 300. There are two properties of ob is operating, the entire object is dependent collection.

In the global search about dep.notify. There are four found. There are three attributes is ob operation. And a method are set del, array.

  • What did the core code defineReactive

This part of the code may be divided into three parts to see: the definition of variables, Object.defineProperty, for childOb operation.

  // 生成一个新的dep。
  const dep = new Dep()
  // 判断这个对象这个属性是否可以修改
  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }
  // 定义getter和setter方法
  const getter = property && property.get
  const setter = property && property.set
  if ((!getter || setter) && arguments.length === 2) {
    val = obj[key]
  }
复制代码
get: function reactiveGetter () {
  // 获取值
  const value = getter ? getter.call(obj) : val
  // 当存在Dep.target的时候进行依赖收集
  if (Dep.target) {
    dep.depend()
    // 省略中间代码
  }
  // 返回获取到的值
  return value
},
set: function reactiveSetter (newVal) {
  // 获取原来的值
  const value = getter ? getter.call(obj) : val
  // 将新的值和原值进行对比,如果没有发生改变,就直接返回
  if (newVal === value || (newVal !== newVal && value !== value)) {
    return
  }
  // 该属性不能set的情况也直接返回
  if (getter && !setter) return
  // 给该属性赋值
  if (setter) {
    setter.call(obj, newVal)
  } else {
    val = newVal
  }
  // 重新对这个值进行监听
  childOb = !shallow && observe(newVal)
  // 更新dep中的watcher
  dep.notify()
}
复制代码
// 尝试将值转化成响应式对象
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()
        // 如果值能呗转化成响应式对象,那么对整个对象进行依赖收集
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      // 省略中间代码
      //因为值发生了变动,所以再一次尝试将其变成一个响应式对象
      childOb = !shallow && observe(newVal)
    }
  })
复制代码
  • Dep.target what actually Dep.target is a global variable, it is a wathcer. In dep source file is as follows:
Dep.target = null
const targetStack = []

export function pushTarget (target: ?Watcher) {
  targetStack.push(target)
  Dep.target = target
}

export function popTarget () {
  targetStack.pop()
  Dep.target = targetStack[targetStack.length - 1]
}
复制代码
  • defineReactive get in when, why judge Dep.target

Since all values ​​in the data is defined, the object will be turned into a responsive, but not necessarily every watcher. watcher divided into three types: render watcher generated, user-defined watcher, computed.

The above process, when generating a new renderWatcher time, will get down process, and then rely on the collection, if not Dep.target, this value does not illustrate corresponding Watcher, there is no need to collect dependency. When the update is time, he returned once dependent on the collection.

Reproduced in: https: //juejin.im/post/5cef2fd66fb9a07ea712f41c

Guess you like

Origin blog.csdn.net/weixin_34088598/article/details/91432012