当前位置: 首页 > news >正文

前端-详解Vue异步更新

目录

一. 什么是异步更新

🌟 什么是“减少不必要的重渲染”?

🚀 “吞吐更高”是啥意思?

🧊 “性能更稳”又是什么鬼?

✨ 总结版:通俗解释

二. 什么时候会“异步”?

三. Vue 是怎么做的?(队列 & 去重 & 微任务)

四. 你需要的“钥匙”:nextTick

五. 一眼看懂的示例

5.1 批处理(batching)与“读旧 DOM”的坑

5.2 列表 & $refs 顺序(你之前就问过这个点!)

六. 和 Watch/Computed 的关系

七. Vue 2 vs Vue 3:调度器差异(重要但不复杂)

八. 高频“为什么”与“怎么做”

九. 实战建议(给你的 Vue2 + Element-UI 项目)

十. 一份迷你清单(面试/复习超好用)


一. 什么是异步更新

        异步更新指:当你连续修改 data/props 时,Vue 不会立刻把每一次变更都渲染到 DOM,而是把这些变更合并(batching)后放到“下一个 tick”统一更新
        这样做的好处:减少不必要的重渲染,吞吐更高、性能更稳。

直观理解:你说“+1、+1、+1”,Vue 先做个笔记:“这个值最终要 +3”,等到本轮同步任务结束,再一次性把 DOM 更新好。

什么是重渲染https://blog.csdn.net/weixin_52159554/article/details/151819344?sharetype=blogdetail&sharerId=151819344&sharerefer=PC&sharesource=weixin_52159554&spm=1011.2480.3001.8118

🌟 什么是“减少不必要的重渲染”?

假设你写了这样的代码:

this.count++
this.name = 'ChatGPT'
this.age = 3000

如果 Vue 每次属性变了就立刻更新 DOM,那这段代码可能会触发 3次 DOM 更新操作

那浏览器得累死,性能嗷嗷掉啊 😫

但 Vue 采用“异步更新+批处理”,它会把这三次数据变更先缓存起来,然后在当前同步代码执行完毕后**,只进行一次 DOM 更新

🎯 所以:

👉 少了两次无谓的 DOM 更新,性能一下就上去了!


🚀 “吞吐更高”是啥意思?

“吞吐量”(throughput)是程序处理大量请求、事件的能力。

Vue 一次处理多个变更,只更新一次 DOM,相当于:

  • 减少了资源浪费

  • 提高了单位时间内能处理的“更新请求”数量

🎯 所以:

👉 系统能“吞”下更多变更,反应也更快!


🧊 “性能更稳”又是什么鬼?

假设你在一个高频率交互场景下,比如:

window.addEventListener('mousemove', () => {this.x++this.y++
})

如果每次鼠标动一下都立刻重渲染 DOM,页面可能会卡顿、掉帧。

但是有了异步更新机制:

  • Vue 会等这一批操作处理完,再一起更新 DOM

  • 页面流畅度明显更好,性能更稳定

🎯 所以:

👉 避免频繁、琐碎的 DOM 改动带来的性能抖动,用户体验更平滑!


✨ 总结版:通俗解释

Vue 的异步更新机制就像是外卖骑手送餐时攒单派送

  • 你点了三杯奶茶(数据更新)

  • 外卖员不立刻跑三次,而是等你点完,一次性送过去(下一 tick 批量更新)

  • 节省人力、时间(CPU、内存),你拿得快,他跑得轻松,双赢!


二. 什么时候会“异步”?

  • 大多数同步代码上下文里(例如事件回调、生命周期钩子、普通函数体内)对响应式数据的修改,都会在同一 tick 被合并,随后统一渲染。

  • 也正因为如此,你在修改完数据的那一行代码后立刻读 DOM,读到的还是旧 DOM


三. Vue 是怎么做的?(队列 & 去重 & 微任务)

  • 队列(queue):每次数据变更会触发相关 watcher/component 的“更新任务”加入队列。

  • 去重(dedupe):相同的 watcher 只会入队一次(用 id 去重),多次修改合并为一次更新。

  • 何时刷新尽可能用“微任务(microtask)”下一个 tick刷新队列(Promise.then 等),环境不支持时用宏任务做兜底(如 setTimeout)。

  • 渲染顺序(简化)

    1. 计算/侦听变更入队 → 2) 下一 tick 刷新队列 → 3) 执行渲染/patch → 4) 触发“更新后”的回调(如 updated$nextTick 回调)。


四. 你需要的“钥匙”:nextTick

        修改数据后,如需读取更新后的 DOM依赖最新布局做计算,用它就对了。

        Vue 2:

// 回调式
this.$nextTick(() => {// 这里 DOM 已经是最新了
});// Promise 式
Vue.nextTick().then(() => {// DOM 已更新
});

        Vue3:

import { nextTick } from 'vue';await nextTick();
// 这里 DOM 已更新

        小口诀:改完数据要看 DOM?nextTick!


五. 一眼看懂的示例

5.1 批处理(batching)与“读旧 DOM”的坑

data() { return { n: 0 }; },
methods: {add() {this.n++;this.n++;console.log('此时数据 n=', this.n); // 2(数据是新的)const el = this.$refs.box;console.log('此时 DOM 文本=', el.textContent); // 仍然是旧的(比如还显示0)this.$nextTick(() => {console.log('nextTick 后 DOM 文本=', el.textContent); // 这时才会是 2});}
}

5.2 列表 & $refs 顺序(你之前就问过这个点!)

<li v-for="todo in todos" :key="todo.id" ref="rows">{{ todo.text }}</li>
<button @click="prepend">在最前插一条</button>
methods: {prepend() {this.todos.unshift({ id: Date.now(), text: 'X' });// 立刻读 $refs.rows:还是旧的顺序console.log(this.$refs.rows.map(li => li.textContent.trim()));this.$nextTick(() => {// 这里才是新顺序console.log(this.$refs.rows.map(li => li.textContent.trim()));});}
}

你那句 const txts = this.$refs.rows.map(li => li.textContent.trim()); 的作用:把所有 li 的文本取出来形成一个字符串数组。但要“取新顺序”,记得放到 $nextTick 里!

六. 和 Watch/Computed 的关系

  • Computed:有缓存,依赖变更才重新求值;多次依赖变更仍被合并到一次更新

  • Watch:数据变了会触发回调;同一 tick 内多次变更可能被合并为一次回调(取决于实现时机)。

  • Vue 3watch 还能指定 flush 时机(见下一节)。

七. Vue 2 vs Vue 3:调度器差异(重要但不复杂)

  • 共同点:都倾向于用微任务队列合并更新,nextTick 语义一致。

  • Vue 3 新增能力watch / watchEffect 可指定回调执行相对渲染的时机:

    • flush: 'pre'(默认):在组件渲染之前执行(同一 tick 内),适合驱动渲染的逻辑

    • flush: 'post'渲染之后执行,天然等价于“带 nextTick 的 watch”,适合读 DOM

    • flush: 'sync'同步立即执行(不排队),谨慎使用,因为可能导致更多渲染。

watch(() => state.value, () => {// 默认 pre:这里的 DOM 还没更新
});watch(() => state.value, () => {// 这里 DOM 已经更新,相当于自动 nextTick
}, { flush: 'post' });

八. 高频“为什么”与“怎么做”

        Q1:为什么我改了数据,DOM 没变?
        A:因为更新是异步批处理;在同一 tick 里 DOM 还没 patch。用 nextTick 读最新 DOM。

        Q2:我连续改了多次,为什么只渲染了一次?
        A:这是去重合并在发挥作用,性能更好。

        Q3:我能强制同步更新吗?
        A:不建议。Vue 2 有 Vue.config.async(仅用于调试,生产不推荐);Vue 3 有 flush: 'sync' 的 watch,但要非常谨慎,容易拖慢性能/引发级联更新。

        Q4:updated 钩子 vs nextTick
        A:updated组件自身更新后触发,适合做与该组件 DOM相关的收尾;nextTick 更灵活:改完数据立刻就能等待“全局” DOM 更新完成,常用于任意位置的“读新 DOM”。

九. 实战建议(给你的 Vue2 + Element-UI 项目)

  1. 所有需要“读 DOM”的逻辑,改数据后包一层 this.$nextTick,包括:

    • $refs(长度、顺序、尺寸)

    • 计算滚动高度、图表容器尺寸(ECharts 重绘)

    • 依赖布局的动画起始值

  2. 批量修改数据时,不要在中间穿插“读 DOM”——统一改完再读一次,减少闪烁。

  3. 复杂联动用队列思维重构:把“改 A 触发 B、改 B 又触发 C”的链条,设计成“本 tick 统一决策 → 下个 tick 一次 patch”,避免抖动。

十. 一份迷你清单(面试/复习超好用)

  • Vue 会把同一 tick 内的多次数据变更合并为一次 DOM 更新

  • 刷新采用微任务优先nextTick 用来等待 DOM 完成更新

  • 读 DOM 放 nextTick,否则大概率读到旧值

  • Vue 2 主要靠 watcher 队列 + 去重;Vue 3 有通用 job queue + flush 选项

  • 仅在必须时考虑同步(flush: 'sync' 等),慎用!

http://www.dtcms.com/a/389663.html

相关文章:

  • 基于风格的对抗生成网络
  • 【JavaScript】SSE
  • JAVA算法练习题day15
  • 线性表---双链表概述及应用
  • 作业帮前端面试(准备)
  • 51单片机-使用单总线通信协议驱动DS18B20模块教程
  • 全文单侧引号的替换方式
  • NVIDIA RTX4090 在Ubuntu系统中开启P2P peer access 直连访问
  • 再次深入学习深度学习|花书笔记2
  • 中移物联ML307C模组OPENCPU笔记1
  • 计算机视觉
  • VScode实现uniapp小程序开发(含小程序运行、热重载等)
  • Redis的各种key问题
  • 元宇宙与医疗产业:数字孪生赋能医疗全链路革新
  • 为你的数据选择合适的分布:8个实用的概率分布应用场景和选择指南
  • 掌握Stable Diffusion WebUI:模型选择、扩展管理与部署优化
  • LVGL拼音输入法优化(无bug)
  • 多层感知机:从感知机到深度学习的关键一步
  • PostgreSQL绿色版整合PostGIS插件,以Windows 64位系统为例
  • GEO优化推荐案例:2025年上海源易信息科技的全链路实践
  • 时空预测论文分享:多模态融合 空间索引结构 超图 时演化因果关系
  • 智能手机产量增长4%
  • MySQL高可用MHA实战指南
  • Coze源码分析-资源库-创建工作流-后端源码-核心技术/总结
  • 《棒球团建》国家级运动健将·棒球1号位
  • 基于STM32单片机生理监控心率脉搏TFT彩屏波形曲线加体温测量
  • Selenium 浏览器自动化完全指南:从环境搭建到实战应用
  • C51单片机——开发学习:中断
  • 树与二叉树【数据结构】
  • RPM包版本号系统解析:设计哲学、比较规则与实践指南