Vue.nextTick核心原理

相信大家在写vue项目的时候,一定会发现一个神奇的api,Vue.nextTick。为什么说它神奇呢,那是因为在你做某些操作不生效时,将操作写在Vue.nextTick内,就神奇的生效了。那这是什么原因呢?

让我们一起来研究一下。

简述

  • vue 实现响应式并不是数据发生变化后 DOM 立即变化,而是按照一定策略异步执行 DOM 更新的

  • vue 在修改数据后,视图不会立刻进行更新,而是要等同一事件循环机制内所有数据变化完成后,再统一进行DOM更新

  • nextTick 可以让我们在下次 DOM 更新循环结束之后执行延迟回调,用于获得更新后的 DOM。

事件循环机制

在讨论Vue.nextTick之前,需要先搞清楚事件循环机制,算是实现的基石了,那我们来看一下。

在浏览器环境中,我们可以将我们的执行任务分为宏任务和微任务,

  • 宏任务: 包括整体代码scriptsetTimeoutsetIntervalsetImmediate、 I/O 操作、UI 渲染
  • 微任务: Promise.thenMuationObserver

Vue.nextTick核心原理_第1张图片

事件循环的顺序,决定js代码的执行顺序。事件循环如下:

Vue.nextTick核心原理_第2张图片

用代码解释,浏览器中事件循环的顺序同如下代码:

for (macroTask of macroTaskQueue) {
    
    // 1. 执行一个宏任务
    handleMacroTask();
    // 2. 执行所有的微任务
    for (microTask of microTaskQueue) {
    
        handleMicroTask(microTask);
    }
 }

vue数据驱动视图的处理(异步变化DOM)

<template>
  <div>
    <div>{
   {
   count}}</div>
    <div @click="handleClick">click</div>
  </div>
</template>
export default {
   
    data () {
   
        return {
   
            number: 0
        };
    },
    methods: {
   
        handleClick () {
   
            for(let i = 0; i < 10000; i++) {
   
                this.count++;
            }
        }
    }
}

分析上述代码:

  • 当点击按钮时,count会被循环改变10000次。那么每次count+1,都会触发count的setter方法,然后修改真实DOM。按此逻辑,这整个过程,DOM会被更新10000次,我们都知道DOM的操作是非常昂贵的,而且这样的操作完全没有必要。所以vue内部在派发更新时做了优化
  • 也就是,并不会每次数据改变都触发 watcher 的回调,而是把这些 watcher 先添加到一个队列queueWatcher里,然后在 nextTick 后执行 flushSchedulerQueue处理
  • 当 count 增加 10000 次时,vue内部会先将对应的 Watcher 对象给 push 进一个队列 queue 中去,等下一个 tick 的时候再去执行。并不需要在下一个 tick 的时候执行 10000 个同样的 Watcher 对象去修改界面,而是只需要执行一个 Watcher 对象,使其将界面上的 0 变成 10000 即可

Vue.nextTick原理

由上一节我们知道,Vue中

你可能感兴趣的:(vue.js)