Vue 中 nextTick 的原理詳解

1. 為什么需要 nextTick

Vue 采用 異步渲染機制,當響應式數據發生變化時,Vue 并不會立即更新 DOM,而是將這些變化放入一個 隊列 中,并在 同一事件循環(Event Loop)中合并相同的修改,最后執行批量更新。這樣做的目的是 提升性能,避免不必要的重復渲染

例如:

<template><div>{{ msg }}</div>
</template><script>
export default {data() {return {msg: "Hello"};},mounted() {this.msg = "Vue";console.log(document.querySelector("div").innerText); // 仍然是 "Hello"this.$nextTick(() => {console.log(document.querySelector("div").innerText); // 現在是 "Vue"});}
};
</script>

為什么 console.log 還是 "Hello"?
因為 Vue 在 this.msg = "Vue"不會立即更新 DOM,而是等本輪事件循環結束后再更新。因此,我們需要 nextTick 來確保獲取到更新后的 DOM。


2. nextTick 的原理

Vue 的 nextTick 本質上是一個 異步任務調度器,它會在當前 DOM 任務完成后執行回調。其內部原理主要依賴 微任務(Microtask)和 宏任務(Macrotask)

2.1 任務隊列

Vue 內部維護了一個 回調隊列(callback queue),當 nextTick 被調用時,它會將回調函數 推入隊列,然后等待 Vue 進行 DOM 更新后,再依次執行這些回調。

2.2 任務調度策略

nextTick 采用 優雅降級 的策略,在不同環境下選擇最佳的異步方法:

  1. Promise(Microtask)(首選,現代瀏覽器支持)
  2. MutationObserver(Microtask)(比 setTimeout 更快)
  3. setImmediate(Macrotask)(僅 IE 支持)
  4. setTimeout(Macrotask)(最后的兜底方案)

代碼實現:

function nextTick(callback) {const p = Promise.resolve();p.then(callback);
}

在 Vue 3 中:

let callbacks = [];
let pending = false;function flushCallbacks() {pending = false;const copies = callbacks.slice(0);callbacks.length = 0;for (let cb of copies) {cb();}
}export function nextTick(cb) {callbacks.push(cb);if (!pending) {pending = true;Promise.resolve().then(flushCallbacks);}
}

流程解析:

  1. 每次調用 nextTick(cb),將 cb 放入 callbacks 隊列中。
  2. 只要 pending === false,就啟動 微任務(Promise.then)
  3. 微任務執行 flushCallbacks,依次調用 callbacks 隊列中的所有回調。

3. nextTick 在 Vue 2 和 Vue 3 的區別

3.1 Vue 2 的 nextTick

在 Vue 2 中,nextTick 主要依賴:

  • Microtask(Promise.then, MutationObserver)
  • Macrotask(setImmediate, setTimeout)
  • 維護了一個 異步任務隊列,用于批量執行 nextTick 回調。

3.2 Vue 3 的 nextTick

Vue 3 主要優化:

  • 只使用 Promise 作為微任務(不再使用 MutationObserver)。
  • 更高效的 異步隊列處理機制

Vue 3 中的 nextTick

const resolvedPromise = Promise.resolve();
export function nextTick(fn) {return fn ? resolvedPromise.then(fn) : resolvedPromise;
}

優化點

  • 直接使用 Promise.resolve().then(fn),避免了 Vue 2 復雜的回調隊列管理。
  • 如果不傳入 fn,則返回一個 Promise,支持 await this.$nextTick()

4. nextTick 的使用場景

4.1 在 DOM 更新后執行操作

<template><div ref="box">{{ message }}</div>
</template><script>
export default {data() {return { message: "Hello" };},methods: {updateMessage() {this.message = "Vue";this.$nextTick(() => {console.log(this.$refs.box.innerText); // "Vue"});}}
};
</script>

4.2 在 watch 中等待 DOM 更新

watch(() => state.count, async (newVal) => {await nextTick();console.log(document.querySelector("#counter").innerText); // 確保 DOM 已更新
});

4.3 在 Vue 3 setup 中使用

import { nextTick, ref } from "vue";setup() {const message = ref("Hello");const updateMessage = async () => {message.value = "Vue";await nextTick();console.log(document.querySelector("#msg").innerText);};return { message, updateMessage };
}


5. 總結

  • nextTick 是 Vue 提供的一個 異步任務調度方法,用于在 DOM 更新后執行回調。
  • Vue 采用 異步批量更新 機制,nextTick 可確保 數據變更后獲取到最新的 DOM
  • Vue 內部采用 Promise(Microtask)優先,降級到 MutationObserver / setTimeout 作為備用方案。
  • Vue 3 進一步優化了 nextTick,減少了不必要的復雜度,提升了性能。

你可以簡單理解為:

Vue 在修改數據后,不會立即更新 DOM,而是 批量合并修改,并在下一次 事件循環(Event Loop)結束時更新 DOMnextTick 讓你可以等到 DOM 更新完成后再執行操作。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/896022.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/896022.shtml
英文地址,請注明出處:http://en.pswp.cn/news/896022.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring面試題2

1、compareable和compactor區別 定義與包位置:Comparable是一個接口&#xff0c;位于java.lang包,需要類去實現接口&#xff1b;而Compactor是一個外部比較器&#xff0c;位于java.util包 用法&#xff1a;Comparable只需要實現int compareTo(T o) 方法&#xff0c;比較當前對…

DuodooBMS源碼解讀之 cncw_statement模塊

財務應收應付擴展模組用戶使用手冊 一、模塊概述 財務應收應付擴展模組是一個基于 Odoo18 的擴展模塊&#xff0c;主要對財務應收應付相關功能進行了修改和增強。該模塊增加了多個功能模塊&#xff0c;如預收款單模塊、費用類別設置模塊等&#xff0c;同時對發票、公司、銷售…

JUC并發—9.并發安全集合四

大綱 1.并發安全的數組列表CopyOnWriteArrayList 2.并發安全的鏈表隊列ConcurrentLinkedQueue 3.并發編程中的阻塞隊列概述 4.JUC的各種阻塞隊列介紹 5.LinkedBlockingQueue的具體實現原理 6.基于兩個隊列實現的集群同步機制 4.JUC的各種阻塞隊列介紹 (1)基于數組的阻塞…

vue項目啟動時報錯:error:0308010C:digital envelope routines::unsupported

此錯誤與 Node.js 的加密模塊有關&#xff0c;特別是在使用 OpenSSL 3.0 及以上版本時。Vue 項目在啟動時可能會依賴一些舊的加密算法&#xff0c;而這些算法在 OpenSSL 3.0 中默認被禁用&#xff0c;導致 error:0308010C:digital envelope routines::unsupported 錯誤。 解決…

ncDLRES:一種基于動態LSTM和ResNet的非編碼RNA家族預測新方法

現有的計算方法主要分為兩類&#xff1a;第一類是通過學習序列或二級結構的特征來預測ncRNAs家族&#xff0c;另一類是通過同源序列之間的比對來預測ncRNAs家族。在第一類中&#xff0c;一些方法通過學習預測的二級結構特征來預測ncRNAs家族。二級結構預測的不準確性可能會導致…

愛普生 SG-8101CE 可編程晶振在筆記本電腦的應用

在筆記本電腦的精密架構中&#xff0c;每一個微小的元件都如同精密儀器中的齒輪&#xff0c;雖小卻對整體性能起著關鍵作用。如今的筆記本電腦早已不再局限于簡單的辦公用途&#xff0c;其功能愈發豐富多樣。從日常輕松的文字處理、網頁瀏覽&#xff0c;到專業領域中對圖形處理…

SPRING10_getBean源碼詳細解讀、流程圖

文章目錄 ①. getBean方法的入口-DefaultListableBeanFactory②. DefaultListableBeanFactory調用getBean③. 進入到doGetBean方法④. getSingleton三級緩存方法⑤. getSingleton()方法分析⑥. createBean創建對象方法⑦. 對象創建、屬性賦值、初始化⑧. getBean最詳細流程圖 ①…

IDEA中查詢Maven項目的依賴樹

在Maven項目中&#xff0c;查看項目的依賴樹是一個常見的需求&#xff0c;特別是當你需要了解項目中直接或間接依賴了哪些庫及其版本時。你可以通過命令行使用Maven的dependency:tree插件來做到這一點。這個命令會列出項目中所有依賴的樹狀結構。 打開idea項目的終端&#xff…

深入xtquant:財務數據獲取與應用的實戰指南

深入xtquant&#xff1a;財務數據獲取與應用的實戰指南 在量化交易領域&#xff0c;雖然技術分析和市場情緒分析占據了主導地位&#xff0c;但財務數據作為評估公司基本面的重要依據&#xff0c;同樣不可或缺。xtquant作為一個強大的Python庫&#xff0c;提供了便捷的接口來獲…

windows 安裝 stable diffusion

在windows上安裝 stable diffusion&#xff0c;如果windows沒有nvidia顯卡&#xff0c;想只使用CPU可在webui-user.bat中添加命令 set COMMANDLINE_ARGS--no-half --skip-torch-cuda-test 可正常使用stable diffusion&#xff0c;但速度較慢

Kubernetes控制平面組件:APIServer 基于 引導Token 的認證機制

云原生學習路線導航頁&#xff08;持續更新中&#xff09; kubernetes學習系列快捷鏈接 Kubernetes架構原則和對象設計&#xff08;一&#xff09;Kubernetes架構原則和對象設計&#xff08;二&#xff09;Kubernetes架構原則和對象設計&#xff08;三&#xff09;Kubernetes控…

DeepSeek 助力 Vue 開發:打造絲滑的縮略圖列表(Thumbnail List)

前言&#xff1a;哈嘍&#xff0c;大家好&#xff0c;今天給大家分享一篇文章&#xff01;并提供具體代碼幫助大家深入理解&#xff0c;徹底掌握&#xff01;創作不易&#xff0c;如果能幫助到大家或者給大家一些靈感和啟發&#xff0c;歡迎收藏關注哦 &#x1f495; 目錄 Deep…

DeepSeek寫俄羅斯方塊手機小游戲

DeepSeek寫俄羅斯方塊手機小游戲 提問 根據提的要求&#xff0c;讓DeepSeek整理的需求&#xff0c;進行提問&#xff0c;內容如下&#xff1a; 請生成一個包含以下功能的可運行移動端俄羅斯方塊H5文件&#xff1a; 核心功能要求 原生JavaScript實現&#xff0c;適配手機屏幕 …

百問網(100ask)的IMX6ULL開發板的以太網控制器(MAC)與物理層(PHY)芯片(LAN8720A)連接的原理圖分析(包含各引腳說明以及工作原理)

前言 本博文承接博文 https://blog.csdn.net/wenhao_ir/article/details/145663029 。 本博文和博文 https://blog.csdn.net/wenhao_ir/article/details/145663029 的目錄是找出百問網(100ask)的IMX6ULL開發板與NXP官方提供的公板MCIMX6ULL-EVK(imx6ull14x14evk)在以太網硬件…

QT開發技術 【opencv圖片裁剪,平均哈希相似度判斷,以及獲取游戲窗口圖片】

一、圖片裁剪 int CJSAutoWidget::GetHouseNo(cv::Mat matMap) {cv::imwrite(m_strPath "/Data/map.png", matMap);for (int i 0; i < 4; i){for (int j 0; j < 6; j){// 計算當前子區域的矩形cv::Rect roi(j * 20, i * 17, 20, 17);// 提取子區域cv::Mat …

TiDB 是一個分布式 NewSQL 數據庫

TiDB 是一個分布式 NewSQL 數據庫。它支持水平彈性擴展、ACID 事務、標準 SQL、MySQL 語法和 MySQL 協議&#xff0c;具有數據強一致的高可用特性&#xff0c;是一個不僅適合 OLTP 場景還適合 OLAP 場景的混合數據庫。 TiDB是 PingCAP公司自主設計、研發的開源分布式關系型數據…

請解釋 Vue 中的生命周期鉤子,不同階段觸發的鉤子函數及其用途是什么?

vue生命周期鉤子詳解&#xff08;Vue 3版本&#xff09; 一、生命周期階段劃分 Vue組件的生命周期可分為四大階段&#xff0c;每個階段對應特定鉤子函數&#xff1a; 創建階段&#xff1a;初始化實例并準備數據掛載階段&#xff1a;將虛擬DOM渲染為真實DOM更新階段&#xff…

計算機專業知識【深入理解子網中的特殊地址:為何 192.168.0.1 和 192.168.0.255 不能隨意分配】

在計算機網絡的世界里&#xff0c;IP 地址是設備進行通信的關鍵標識。對于常見的子網&#xff0c;如 192.168.0.0/24&#xff0c;我們可能會疑惑為何某些地址不能分配給主機使用。接下來&#xff0c;我們就以 192.168.0.0/24 為例&#xff0c;詳細解釋為何 192.168.0.1 和 192.…

軟件架構設計:軟件工程

一、軟件工程概述 軟件工程的定義 軟件工程是應用系統化、規范化、可量化的方法開發、運行和維護軟件。 軟件工程的目標 提高軟件質量、降低開發成本、縮短開發周期。 軟件生命周期 瀑布模型&#xff1a;需求分析→設計→編碼→測試→維護。迭代模型&#xff1a;分階段迭代開…