📚前端面试题速记
Q8

Vue 3 是如何处理异步更新队列的?

速记答案(30 秒)

状态变化时不立刻更新 DOM,而是把相关副作用/组件放入队列并打标为"脏"。使用微任务在同一 tick 批量 flush 队列。

📖 详细讲解

标准面试回答(推荐记住)

Vue 3 采用异步更新策略。当响应式数据变化时,不会立即更新 DOM,而是将更新任务放入队列并标记为脏。然后使用 Promise.then 等微任务机制,在同一个事件循环中批量处理队列。这样可以合并多次修改,避免重复渲染,且保证父组件先于子组件更新。

异步更新调度机制

核心流程:

  1. 触发更新:响应式数据变更触发 Setter -> Trigger -> Effect Scheduler。
  2. 入队 (queueJob):将 Effect 任务推入全局 queue 数组,并通过 IDs 去重(防止同一组件多次更新)。
  3. 微任务 (Microtask):通过 Promise.resolve().then(flushJobs) 启动微任务。
  4. 刷新队列 (flushJobs)
    • 对队列进行排序(保证父组件先于子组件更新,因为父组件 ID 小)。
    • 依次执行 Effect.run() 进行 Patch。
    • 执行生命周期钩子(updated)和 watch 回调。

为什么是微任务?
微任务在当前宏任务结束后、渲染前立即执行,保证在一次事件循环中完成所有数据变更,合并 DOM 操作,性能最优。

面试要点

  • 理解异步更新的性能优势
  • 知道更新队列的执行时机
  • 掌握 nextTick 的使用场景

💻 代码示例

异步更新与 nextTick
import { ref, nextTick } from 'vue'

const count = ref(0)


// 同步修改多次
count.value++
count.value++
count.value++
// 实际只会触发一次 DOM 更新

// 需要等待 DOM 更新完成
async function updateAndRead() {
  count.value = 100
  // 此时 DOM 还没更新
  console.log(document.querySelector('#count')?.textContent) // 旧值
  
  await nextTick()
  // DOM 已更新
  console.log(document.querySelector('#count')?.textContent) // 100
}