Serie -4- Vue Vue fuente utilizando el procesamiento asíncrono, y por qué el principio

¿Por qué el procesamiento asíncrono?


Porque si no se utiliza actualización asíncrona, a continuación, los datos se actualizan cada vez que la componente de corriente es re-emitida, lo que probablemente sería una gran cantidad de re-dom arroyo o vuelve a dibujar, por lo que con el fin de considerar el rendimiento y reducir los datos del navegador en cada actualización Vue Dom apareció por encima, Vue será después de la actual ronda de actualizaciones de datos, vaya a actualizar de forma asíncrona la vista!


src / core / observador / index.js
método setter definido en defineReactive (), esta vez no () método dep.notify

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() // 触发数据对应的依赖进行更新
    }
  })
}

Luego, busquen en notify()el método de
src / core / observador / dep.js

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方法
    }
  }
}

Esto se debe principalmente a hacer es notificar a la operación de actualización observador, sino también una operación de ordenación, y, finalmente, a su vez llama la actualización de cada observador () método,

A continuación, busque en este update ()método

src / core / observador / watcher.js

export default class Watcher {
  /**
   * Subscriber interface.
   * Will be called when a dependency changes.
   */
  update () {
    /* istanbul ignore else */
    if (this.lazy) {
      this.dirty = true
    } else if (this.sync) { // 同步watcher
      this.run()
    } else {
      queueWatcher(this) // 
    }
  }
}

Aquí es una queueWatcher() 方法

src / core / observador / scheduler.js

/**
 * Push a watcher into the watcher queue.
 * Jobs with duplicate IDs will be skipped unless it's
 * pushed when the queue is being flushed.
 */
export function queueWatcher (watcher: Watcher) {
  const id = watcher.id // 过滤watcher  多个属性依赖同一个watcher
  if (has[id] == null) {
    has[id] = true
    if (!flushing) {
      queue.push(watcher) // 将watcher放到队列中
    } else {
      // if already flushing, splice the watcher based on its id
      // if already past its id, it will be run next immediately.
      let i = queue.length - 1
      while (i > index && queue[i].id > watcher.id) {
        i--
      }
      queue.splice(i + 1, 0, watcher)
    }
    // queue the flush
    if (!waiting) {
      waiting = true

      if (process.env.NODE_ENV !== 'production' && !config.async) {
        flushSchedulerQueue()
        return
      }
      nextTick(flushSchedulerQueue) 
    }
  }
}

Dentro de este método hace dos cosas

  1. Mediante la adición de un atributo id a cada observador, es decir, operación de eliminación de datos duplicados, para filtrar la pluralidad de atributo dependiente mismo observador observador
  2. queue.push (observador), el observador en la cola
  3. Método última llamada nextTick (), para dejar en claro las operaciones asincrónicas de cola observador

Este método puede ser un maullido (flushSchedulerQueue), una función de orden superior usando interna
watcher.before ()
se lleva a cabo el método realmente ejecutar

function flushSchedulerQueue () {
  currentFlushTimestamp = getNow()
  flushing = true
  let watcher, id

  // Sort queue before flush.
  // This ensures that:
  // 1. Components are updated from parent to child. (because parent is always
  //    created before the child)
  // 2. A component's user watchers are run before its render watcher (because
  //    user watchers are created before the render watcher)
  // 3. If a component is destroyed during a parent component's watcher run,
  //    its watchers can be skipped.
  queue.sort((a, b) => a.id - b.id)

  // do not cache length because more watchers might be pushed
  // as we run existing watchers
  for (index = 0; index < queue.length; index++) {
    watcher = queue[index]
    if (watcher.before) {
      watcher.before() // before方法
    }
    id = watcher.id
    has[id] = null
    watcher.run() // 执行watcher
    // in dev build, check and stop circular updates.
    if (process.env.NODE_ENV !== 'production' && has[id] != null) {
      circular[id] = (circular[id] || 0) + 1
      if (circular[id] > MAX_UPDATE_COUNT) {
        warn(
          'You may have an infinite update loop ' + (
            watcher.user
              ? `in watcher with expression "${watcher.expression}"`
              : `in a component render function.`
          ),
          watcher.vm
        )
        break
      }
    }
  }

  // keep copies of post queues before resetting state
  const activatedQueue = activatedChildren.slice()
  const updatedQueue = queue.slice()

  resetSchedulerState()

  // call component updated and activated hooks
  callActivatedHooks(activatedQueue)
  callUpdatedHooks(updatedQueue) // 更新后调用的 updated

  // devtool hook
  /* istanbul ignore if */
  if (devtools && config.devtools) {
    devtools.emit('flush')
  }
}

Bajo el principio de breve resumen:

  1. Llamar para notificar () para informar a las operaciones de actualización del vigilante
  2. El método de actualización a su vez llama observador
  3. operación Deduplication se realiza en el observador (por id), en la cola de
  4. Después de la aplicación de la cola asíncrona vaciar, nextTick (flushSchedulerQueue) la operación de actualización masiva
Publicado 65 artículos originales · ganado elogios 100 · vistas 310 000 +

Supongo que te gusta

Origin blog.csdn.net/qq_36407748/article/details/105170923
Recomendado
Clasificación