nexitTick的作用及原理


1. 作用

将值赋给data后是不立即更新的。这时候就需要用nextTick对更新后的dom节点做操作

2. 使用

this.$nextTick(function () {
  console.log(this.$el.textContent) // => '已更新'
})
await this.$nextTick()
// => '已更新'

3. 原理

为了避免不必要的计算和 DOM 操作,vue将DOM更新设计为异步。nextTick是一个微任务,返回一个promise,可以对更新后的dom进行一些操作。

https://v2.cn.vuejs.org/v2/guide/reactivity.html#%E5%BC%82%E6%AD%A5%E6%9B%B4%E6%96%B0%E9%98%9F%E5%88%97

注意:这里不需要关心事件循环中的渲染。就像下面示例,图片被alert阻塞未渲染,这已经能拿到高度了。

<script>
    let imgDom = document.createElement("img");
    imgDom.setAttribute("id", "myimg");
    imgDom.setAttribute("width", "200px");
    imgDom.setAttribute("height", "200px");
    imgDom.setAttribute("src", "https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/c995d143ad4bd113fceedf775bafa40f4bfb0557.jpg");

    let body = document.querySelector("body");
    console.log("附加前高度", body.offsetHeight);//400
    body.append(imgDom);
    console.log("附加前高度", body.offsetHeight);//600
    alert('暂停')

</script>

4. nextTick 为什么是 next tick?

从字面意思理解,next 下一个,tick 滴答(钟表)来源于定时器的周期性中断(输出脉冲),一次中断表示一个 tick,也被称做一个“时钟滴答”,nextTick 顾名思义就是下一个时钟滴答,下一个任务。下一个任务,在 Event Loop 中在熟悉不过了通过一个例子简单回忆一下 Event Loop。

console.log('同步代码1');
setTimeout(() => {
    console.log('setTimeout')
}, 0)
new Promise((resolve) => {
  console.log('同步代码2')
  resolve()
}).then(() => {
    console.log('promise.then')
})
console.log('同步代码3');
// 最终输出"同步代码1"、"同步代码2"、"同步代码3"、"promise.then"、"setTimeout"

第一个 tick(图例中第一个步骤,即’本次更新循环’)
首先修改数据,这是同步任务。同一事件循环的所有的同步任务都在主线程上执行,形成一个执行栈,此时还未涉及 DOM 。
Vue 开启一个异步队列,并缓冲在此事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。

同步任务在主线程执行,这是第一个 task。

第二个 tick(图例中第二个步骤,即’下次更新循环’)
同步任务执行完毕,开始执行异步 watcher 队列的任务,更新 DOM 。Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MO,如果执行环境不支持,会采用 setImmediate 或者是 setTimeout(fn, 0) 代替(不同 Vue 版本 API 不一样)。

DOM 更新是第二个 task 。

第三个 tick(图例中第三个步骤)
当 DOM 更新循环结束之后,此时调用下一个 task 执行,也就是 nextTick 中注册的延迟回调 。$nextTick 其实和第二个 task 是一样的操作,但是属于不同的 task。

也就是第三个 task。


文章作者: iamfugui
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 iamfugui !
评论
  目录