nextTick

博客介绍了Vue.js异步更新视图的原理。在mounted时test值多次++,若无异步更新会频繁操作DOM,消耗性能。Vue.js通过queue队列统一执行Watcher的run,优化性能。还提及JS的event loop,区分task和microtask,介绍创建新microtask的方法及使用microtask的原因,以及nextTick的目的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异步更新视图

<template>
  <div>
    <div>{{test}}</div>
  </div>
</template>
export default {
    data () {
        return {
            test: 0
        };
    },
    mounted () {
      for(let i = 0; i < 1000; i++) {
        this.test++;
      }
    }
}

现在有这样的一种情况,mounted的时候test的值会被++循环执行1000次。 每次++时,都会根据响应式触发setter->Dep->Watcher->update->patch。 如果这时候没有异步更新视图,那么每次++都会直接操作DOM更新视图,这是非常消耗性能的。 所以Vue.js实现了一个queue队列,在下一个tick的时候会统一执行queue中Watcher的run。同时,拥有相同id的Watcher不会被重复加入到该queue中去,所以不会执行1000次Watcher的run。最终更新视图只会直接将test对应的DOM的0变成1000。 保证更新视图操作DOM的动作是在当前栈执行完以后下一个tick的时候调用,大大优化了性能。

JS 的 event loop 执行时会区分 task 和 microtask,引擎在每个 task 执行完毕,从队列中取下一个 task 来执行之前,会先执行完所有 microtask 队列中的 microtask。
setTimeout 回调会被分配到一个新的 task 中执行,而 Promise 的 resolver、MutationObserver 的回调都会被安排到一个新的 microtask 中执行,会比 setTimeout 产生的 task 先执行。
要创建一个新的 microtask,优先使用 Promise,如果浏览器不支持,再尝试 MutationObserver。
实在不行,只能用 setTimeout 创建 task 了。
为啥要用 microtask?
根据 HTML Standard,在每个 task 运行完以后,UI 都会重渲染,那么在 microtask 中就完成数据更新,当前 task 结束就可以得到最新的 UI 了。
反之如果新建一个 task 来做数据更新,那么渲染就会进行两次。

nextTick的目的就是产生一个回调函数加入task或者microtask中,当前栈执行完以后(可能中间还有别的排在前面的函数)调用该回调函数,起到了异步触发(即下一个tick时触发)的目的。

### Node.js 中 `process.nextTick` 的作用 `process.nextTick` 是 Node.js 提供的一个异步编程工具,用于将回调函数推迟到当前操作完成后立即执行。它将指定的回调函数插入到一个称为“next tick 队列”的特殊队列中,该队列会在当前事件循环的当前阶段结束后、进入下一个阶段之前被处理。这意味着 `process.nextTick` 的回调会在下一个事件循环迭代开始之前执行,因此它比其他异步操作(如 `setTimeout` 或 `setImmediate`)具有更高的优先级[^3]。 在 Node.js 中,事件循环的每次迭代被称为一个“tick”。通过 `process.nextTick`,开发者可以确保某些任务在当前同步操作完成后立即执行,而不会阻塞主线程。这种机制特别适用于需要快速响应的场景,例如在异步函数链中插入一个回调,或者在事件循环的下一次迭代中处理某些清理或初始化任务[^4]。 ### Node.js 中 `process.nextTick` 的使用方法 `process.nextTick` 的基本使用方法非常简单,只需要传入一个回调函数即可: ```javascript process.nextTick(() => { console.log('This will run in the next tick'); }); ``` 在实际应用中,`process.nextTick` 常用于以下场景: - **避免阻塞当前操作**:当需要在当前同步操作完成后执行某些异步操作时,可以使用 `process.nextTick` 将这些操作推迟到下一个 tick 执行,从而避免阻塞当前操作。 - **确保某些操作在事件循环的下一个周期中执行**:例如,在某些异步函数中,可能需要确保某些初始化或清理操作在当前函数返回后立即执行。 - **实现链式调用**:在 Node.js 的模块系统中,`process.nextTick` 被广泛用于实现异步链式调用,例如在 `EventEmitter` 的 `on` 和 `emit` 方法中。 ### 与浏览器端 `nextTick` 的区别 需要注意的是,Node.js 的 `process.nextTick` 与浏览器端的 `Vue.nextTick` 或 `MutationObserver` 等机制不同。在浏览器环境中,类似的功能通常通过 `setTimeout(fn, 0)` 来实现,这实际上是一个宏任务,执行优先级低于微任务。而在 Node.js 中,`process.nextTick` 是一个微任务,其回调会在当前事件循环的下一个阶段之前执行,因此具有更高的优先级[^2]。 ### 使用 `process.nextTick` 的注意事项 尽管 `process.nextTick` 是一个非常有用的工具,但在使用时也需要注意以下几点: - **避免滥用**:过度使用 `process.nextTick` 可能会导致事件循环被频繁打断,从而影响性能。 - **调试困难**:由于 `process.nextTick` 的回调执行时机较为特殊,可能会导致调试时难以追踪某些异步行为。 - **递归调用问题**:如果在 `process.nextTick` 的回调中再次调用 `process.nextTick`,可能会导致事件循环被无限推迟,从而引发性能问题甚至阻塞整个程序[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值