Vue3的渲染秘密:从同步批处理到异步微任务

面试里,当面试官把两段看似「都是改 5 次数据」的代码摆在你面前,却问「渲染了几次?」,如果你只回答「改了 5 次所以 5 次」,那大概率就踩坑了。本文用 100 行代码把同步批处理与异步微任务的底层机制拆开讲透,让你以后遇到同类问题直接秒答。

一、手写一个带合并渲染的 Component

需求

  1. 修改数据时触发 render
  2. 同步多次修改只触发一次 render

实现思路

利用 微任务队列 把同一次事件循环里的多次 set 合并到下一帧执行。

js 复制代码
class Component {
  data = { name: '' }
  _pending = false          // 标记位:是否有未 flush 的修改

  constructor() {
    // 通过 Proxy 拦截所有属性写入
    this.data = new Proxy(this.data, {
      set: (target, key, value) => {
        target[key] = value
        this.scheduleRender()
        return true
      }
    })
  }

  scheduleRender() {
    if (this._pending) return   // 已在队列中,跳过
    this._pending = true
    queueMicrotask(() => {
      this.render()
      this._pending = false
    })
  }

  render() {
    console.log(`render - name: ${this.data.name}`)
  }
}

// 测试
const com = new Component()
com.data.name = '张三'
com.data.name = '李四'
com.data.name = '王五'
setTimeout(() => com.data.name = '巷子', 0)

输出顺序:

arduino 复制代码
render - name: 王五      // 第一帧批处理
render - name: 巷子      // setTimeout 宏任务

核心原理:queueMicrotask 把多次写操作合并到同一微任务阶段,只执行一次 render

二、Vue 中同步 vs 异步赋值到底渲染几次?

代码一:同步 for 循环

vue 复制代码
<script setup>
import { ref } from 'vue'
const rCount = ref(0)
for (let i = 1; i <= 5; ++i) {
  rCount.value = i
}
</script>

渲染次数:2 次

  1. 初始挂载:渲染 0
  2. 批处理队列:5 次赋值被合并,最终渲染 5

Vue 内部使用 异步队列(queueJob) 收集同步变更,下一事件循环统一 flush。同一代码块内无论改多少次,都只走一次 DOM diff。

代码二:setTimeout 异步循环

vue 复制代码
<script setup>
import { ref } from 'vue'
const rCount = ref(0)
for (let i = 1; i <= 5; ++i) {
  setTimeout(() => rCount.value = i, 0)
}
</script>

渲染次数:6 次

  1. 初始挂载:渲染 0
  2. 每个 setTimeout 回调都是一个独立宏任务,Vue 的批处理无法跨任务合并,于是 5 次回调触发 5 次独立渲染。

总结

同步代码 → 全部进入同一批处理队列 → 1 次渲染

异步代码 → 每次回调独立任务 → n 次渲染

相关推荐
AC赳赳老秦17 小时前
公开图片 OCR 数据提取:OpenClaw 合规采集公开信息图,识别文字与表格并转化为结构化数据
java·大数据·前端·数据库·python·php·openclaw
谢慧琼17 小时前
2026零基础做企业网站,低成本搭建官方网站
服务器·前端·javascript
weixin_4316004418 小时前
前端数据埋点(1):一次点击如何变成一条埋点
前端·js·数据埋点
IT_陈寒18 小时前
Python线程池吞了异常还不告诉我,这谁顶得住啊
前端·人工智能·后端
计算机魔术师19 小时前
同样是AI辅助建造,为什么有的游戏三个月就烂尾了?
前端
用户9210802628619 小时前
0. 做 Agent 产品,前端 AI 组件框架怎么选?
前端
库玛西19 小时前
现代 C++ 智能指针全景指南:从 RAII 思想到工业级实践
c语言·开发语言·c++·笔记·面试
拾年27520 小时前
React Hooks 进阶篇:useMemo / useCallback / useReducer / useImperativeHandle,用「算账 +
前端·javascript·react.js
Jackson__20 小时前
面试官:如何在老项目中使用新框架,并实现通信?
前端·javascript·面试
拾年27520 小时前
React Hooks 保姆级教程:把组件想象成失忆的打工人,4 个 Hook 带你原地起飞
前端·javascript·react.js