异步渲染和nextTick

254 阅读1分钟

异步渲染

Vue可以响应数据变化,数据变化后会自动更新视图,如果每次修改都触发视图更新,会导致多次重复和不必要的渲染操作,例如一个组件使用了两个data的属性,更新两个属性如果触发两次渲染的话,会影响性能。因此Vue采取异步更新。

每次更新响应的属性之后,会将渲染的watcher放到一个队列中,在下个事件循环中再执行。

整个更新渲染的过程是:

  1. data的属性更新
  2. 通知依赖的render
  3. render的watcher加入队列(队列去重)
  4. nextTick清空watcher队列,执行各watcher中的回调

示例:

// 改变数据
vm.message = 'changed';

// 想要立即使用更新后的DOM。这样不行,因为设置message后DOM还没有更新
console.log(vm.$el.textContent); // 并不会得到'changed'

// nextTick里面的代码会在DOM更新后执行
Vue.nextTick(function(){
  console.log(vm.$el.textContent) //可以得到'changed'
});

nextTick

在了解nextTick之前,需要先理解JavaScript的任务队列。

Vue.nextTick()方法用来设置让方法在下一个事件队列中执行。

Vue使用MutationObserver/Promise/setTimeout实现nextTick。Vue判断浏览器兼容性,按照MutationObserver -> Promise -> setTimeout的优先级实现nextTick。

Promise和setTimeout比较好理解,使用MutationObserver的目的是为了将回调加入到微任务队列,比宏任务队列更早执行。

我们知道,NodeJS中也有一个process.nextTick方法,也是用来设置回调异步,在下个循环中执行,但是这个方法并未将任务加入到宏任务队列或者微任务队列,它是将任务加到下次事件循环之前。