Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

为什么Vue采用异步渲染? #109

Open
Cosen95 opened this issue Apr 25, 2020 · 1 comment
Open

为什么Vue采用异步渲染? #109

Cosen95 opened this issue Apr 25, 2020 · 1 comment
Labels

Comments

@Cosen95
Copy link
Owner

Cosen95 commented Apr 25, 2020

No description provided.

@Cosen95 Cosen95 added the vue label Apr 25, 2020
@Cosen95
Copy link
Owner Author

Cosen95 commented Apr 25, 2020

我们先来想一个问题:如果Vue不采用异步更新,那么每次数据更新时是不是都会对当前组件进行重写渲染呢?

答案是肯定的,为了性能考虑,会在本轮数据更新后,再去异步更新视图。

通过一张图来说明Vue异步更新的流程:

  • 第一步调用dep.notify()通知watcher进行更新操作。对应源码src/core/observer/dep.js中的37行。
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方法
  }
}
  • 第二步其实就是在第一步的notify方法中,遍历subs,执行subs[i].update()方法,也就是依次调用watcherupdate方法。对应源码src/core/observer/watcher.js的164行
/**
 * 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)  // 当数据发生变化时会将watcher放到一个队列中批量更新
  }
}
  • 第三步是执行update函数中的queueWatcher方法。对应源码src/core/observer/scheduler.js的164行。
/**
 * 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)  // 调用nextTick方法,在下一个tick中刷新watcher队列
    }
  }
}
  • 第四步就是执行nextTick(flushSchedulerQueue)方法,在下一个tick中刷新watcher队列

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant