Vue學習之---nextTick

前言:目前來說,nextTick我們遇到的比較少,至少對我來說是這樣的,但是有一些聰明的小朋友早早就注意到這個知識點了。nextTick 是前端開發(尤其是 Vue 生態)中的核心知識點,原理上跟Vue的異步更新有密切關系,對于面試者考察很有區分度,如果能回答的很好,對面試也是很有幫助的,所以我們有必要花費時間來學習一下。

一、nextTick是什么

我們來看看官方的定義:

在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM。

看完是不是有一堆問號?沒關系,我們來拆分一下關鍵詞

下次 DOM 更新循環結束之后

延遲回調

更新后的 DOM

1、 下次 DOM 更新循環結束之后

Vue更新DOM是有策略的,不是同步更新,是異步的,批量更新DOM,避免重繪導致的性能損耗(比如連續修改數據時僅觸發一次渲染)

如果你學過防抖和節流的話,有沒有感覺這里邏輯有點相像,他們都是前端性能優化手段,那么我們順便就來復習一下吧。

他們有著共同目標:減少高頻操作帶來的性能損耗。

實現邏輯上的對比:

機制Vue異步更新防抖(Debounce)節流(Throttle)
觸發條件數據變化事件觸發(如resize)事件觸發(如scroll)
執行策略合并同一事件循環內的所有修改延遲執行,僅保留最后一次操作固定間隔執行一次
應用場景虛擬DOM批量渲染搜索框輸入聯想滾動加載更多

核心區別:

Vue異步更新:

  • 依賴瀏覽器事件循環

  • 自動完成,開發者無需手動控制

防抖/節流:

  • 需開發者顯式編碼實現

  • 作用于業務邏輯層而非框架底層

    呼~復習完了,我們進入正題

    這個關鍵詞跟瀏覽器的事件循環有關,我們來簡單回顧一下:

    瀏覽器事件循環

    JS是一門單線程的語言,因為它運行在瀏覽器的渲染主線程中,而主線程只有一個。而渲染主線程承擔著許多的工作,渲染頁面、執行JS都在其中執行。如果使用同步的方式,極有可能導致主線程產生阻塞,從而導致消息隊列中的許多其他任務無法得到執行,所以瀏覽器采用異步的方式來避免。

    ?console.log('腳本開始') setTimeout(() => console.log('定時器'), 0) Promise.resolve().then(() => {console.log('Promise') setTimeout(() => console.log('嵌套定時器'), 0) })console.log('腳本結束') ???
    ??輸出:/* 輸出順序:腳本開始腳本結束Promise定時器嵌套定時器*/

    2、延遲回調

    這里的"延遲"不是指setTimeout那樣的宏任務延遲,而是指將回調函數推入微任務隊列(microtask queue)等待執行。Vue會根據運行環境自動選擇最優的實現方式:

    • 優先使用 Promise.then()

      • 如果當前環境支持 Promise,Vue 會優先使用 Promise.then() 來實現微任務。

      • 這是現代瀏覽器中最高效的方式,因為它直接利用了 JavaScript 的微任務機制。

    • 降級方案:MutationObserver

      • 如果當前環境不支持 Promise,但支持 MutationObserver,Vue 會使用 MutationObserver 作為替代方案。

      • MutationObserver 的回調會被加入微任務隊列,雖然它主要用于監聽 DOM 變化,但也可以用來實現微任務的效果。

    • 降級方案:setImmediate

      • 如果當前環境不支持 PromiseMutationObserver,但支持 setImmediate,Vue 會使用 setImmediate

      • setImmediate 是 Node.js 和 IE10+ 提供的一種機制,雖然它是宏任務,但它的執行時機比 setTimeout(fn, 0) 更早。

    • 兜底方案:setTimeout(fn, 0)

      • 如果當前環境不支持 PromiseMutationObserversetImmediate,Vue 會使用 setTimeout(fn, 0) 作為兜底方案。

      • 雖然 setTimeout(fn, 0) 是宏任務,但它是最通用的實現方式,確保在當前同步代碼執行完畢后執行回調。

    3、更新后的 DOM

    由于Vue的響應式更新是異步的,直接修改數據后立即訪問DOM獲取的是舊值。通過nextTick可以確保獲取到的是最新渲染結果:

    ?<script setup>import { ref, nextTick } from 'vue';?const num = ref(0);?const changeValue = async () => {num.value = 1; // 更新數據console.log('第一次打印:', num.value); // 打印當前數據console.log('第一次 DOM:', document.querySelector('div').textContent); // 打印當前 DOM 內容?await nextTick(); // 等待 DOM 更新完成?console.log('第二次打印:', num.value); // 打印當前數據console.log('第二次 DOM:', document.querySelector('div').textContent); // 打印更新后的 DOM 內容};?</script><template><div>{{ num }}</div><button @click="changeValue">Change</button></template>?

    打印結果:

  • 第一次打印:1

  • 第一次打印DOM:0

  • 第二次打印:1

  • 第二次打印DOM:1

  • 總的來說,nextTick就是一個工具,用來確保在 Vue 更新完 DOM 之后,再執行某些操作。它特別有用,因為有時候你修改了數據,Vue 需要一點時間來更新 DOM,而 nextTick 可以讓你在 DOM 更新完成之后,立即執行你需要的操作。

    二、使用場景

    1. DOM依賴型操作

    • 獲取更新后的元素尺寸/位置

    • 基于新DOM初始化第三方庫(如圖表庫)

    <template><div><h1>Vue 3 nextTick 示例</h1><button @click="loadData">Load Data</button></div></template>?<script setup>import { ref, nextTick } from 'vue';?const dataLoaded = ref(false);?function loadData() {// 模擬數據加載dataLoaded.value = true;?// 確保數據已渲染到 DOMnextTick(() => {initChart();});}?function initChart() {console.log('Chart initialized');// 在這里初始化圖表}</script>

    2. 組件通信

    父子組件生命周期執行順序導致的問題:

    <template><div><button @click="showChild">Show Child</button><ChildComponent v-if="isShow" ref="child" /></div></template>?<script setup>import { ref, nextTick } from 'vue';import ChildComponent from './ChildComponent.vue';?const isShow = ref(false);?function showChild() {isShow.value = true; // 顯示子組件nextTick(() => {const child = $refs.child; // 獲取子組件的引用if (child) {child.doSomething(); // 確保子組件已掛載并調用方法}});}</script>

    3. 特殊交互處理

    如自動聚焦輸入框:

    ?<template><div><button @click="showInputAndFocus">Show Input and Focus</button><input v-if="showInput" ref="input" /></div></template>?<script setup>import { ref, nextTick } from 'vue';?const showInput = ref(false);?function showInputAndFocus() {showInput.value = true; // 顯示輸入框nextTick(() => {const inputElement = $refs.input; // 獲取輸入框的引用if (inputElement) {inputElement.focus(); // 聚焦到輸入框}});}</script>

    • 同步代碼執行完畢后,事件循環開始處理微任務隊列。

    • 執行微任務隊列中的 Promise 回調,輸出 Promise

    • Promise 回調中,setTimeout(() => console.log('嵌套定時器'), 0) 被加入宏任務隊列。

    • 微任務隊列清空后,事件循環開始處理宏任務隊列。

    • 執行第一個宏任務 setTimeout(() => console.log('定時器'), 0),輸出 定時器

    • 執行第二個宏任務 setTimeout(() => console.log('嵌套定時器'), 0),輸出 嵌套定時器

    • 執行順序:同步代碼 → 微任務隊列 → 宏任務隊列

    • 同步代碼執行:首先執行當前的同步代碼。

    • 清空微任務隊列:在同步代碼執行完畢后,事件循環會立即清空微任務隊列,依次執行微任務隊列中的所有任務。

    • 執行宏任務:清空微任務隊列后,事件循環會從宏任務隊列中取出一個任務執行。

    • 重復步驟 2 和 3:每次執行完一個宏任務后,事件循環會再次清空微任務隊列,然后繼續執行下一個宏任務。

    • 宏任務:通常用于延遲執行、異步操作或與瀏覽器的 UI 渲染相關。它們的執行時機在事件循環的每次迭代中,每次只執行一個。(setTimeoutsetInterval setImmediate I/O 操作 UI 渲染

    • 微任務:通常用于需要在當前任務執行完畢后立即執行的回調。它們的優先級高于宏任務,會在每次宏任務執行完畢后立即清空。(Promise MutationObserver queueMicrotask)

    • 注意,這里為了方便理解,我們把任務籠統歸類為宏任務和微任務,現在對于宏任務和微任務已經有了更細的劃分,大家可以去了解一下,但是這里只是為了讓大家方便理解,采用了宏任務和微任務的說法,其實也是對的,但是這樣說比較舊

三、實戰測試

測試案例1:驗證執行順序

猜猜最后打印出什么結果

<template><div><h1>Vue 3 nextTick 示例</h1></div></template>?<script setup>import { onMounted, nextTick } from 'vue';?onMounted(() => {console.log('1');Promise.resolve().then(() => console.log('2'));nextTick(() => console.log('3'));setTimeout(() => console.log('4'), 0);});</script>

打印:1234

首先執行同步操作,打印1

執行微隊列的任務promise和nextTick,打印2和3

執行宏隊列任務,打印4

測試案例2:連續修改測試

猜猜最后打印出什么結果

?
<template><div><h1>Vue 3 nextTick 示例</h1><button @click="testBatchUpdate">Test Batch Update</button></div></template>?<script setup>import { ref, nextTick } from 'vue';?const count = ref(0);?function testBatchUpdate() {count.value = 1;nextTick(() => console.log(count.value));count.value = 2;nextTick(() => console.log(count.value));}</script>

打印:22

先執行同步操作,先后吧count的值改為1和2,然后執行微隊列的任務,打印兩次count的值

四、面試常問

整理了一些面視可能會問的問題

1. 核心原理

Q:nextTick的實現原理是什么? A:基于JavaScript事件循環機制,優先使用微任務隊列實現異步回調。Vue會維護一個回調隊列,在同一個tick中多次調用nextTick只會向隊列添加任務,最終通過異步API批量執行。

2. 執行時機

Q:nextTick與setTimeout(fn, 0)的區別? A:nextTick會優先使用微任務(執行早于setTimeout),且能自動選擇最優的異步方案。setTimeout屬于宏任務,執行時機更晚。

3. 與Vue響應式的關系

Q:為什么Vue選擇異步更新DOM? A:主要考慮兩點:

  1. 性能優化:合并同一事件循環中的所有數據變更

  2. 邏輯合理性:確保無論修改多少次數據,組件只更新一次

4. 特殊場景

Q:nextTick回調中再修改數據會怎樣? A:會進入新的更新周期,可能觸發額外的渲染。應避免這種嵌套使用。

Q:為什么 nextTick 回調中修改數據可能導致額外渲染? A:因為 nextTick 回調執行時,當前渲染周期已結束。若在回調中修改數據,會觸發新的渲染周期(類似“連鎖反應”)。

5. nextTick的常見使用場景有哪些

  • A

    1、確保 DOM 更新完成后執行某些操作(如獲取元素尺寸、滾動位置等)。

    2、在子組件掛載后執行某些操作(如調用子組件的方法)。

    3、在批量更新數據后,確保所有更新完成后再執行某些操作。

    6. nextTick如何幫助優化性能

    • A

      • 通過確保在 DOM 更新完成后執行回調,nextTick 可以避免在 DOM 更新過程中進行不必要的操作,從而減少性能開銷。

        上面只是一部分,多的大家可以自己下去搜索一些

五、致謝

bilibili 瀏覽器事件循環原理嗶哩嗶哩bilibili

官方網站 nextTick | Vue3

騰訊元寶 豆包 kimi

我自己 😎😋

愛學習的你們👏🌹

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

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

相關文章

MS2691 全頻段、多模導航、射頻低噪聲放大器芯片,應用于導航儀 雙頻測量儀

MS2691 全頻段、多模導航、射頻低噪聲放大器芯片&#xff0c;應用于導航儀 雙頻測量儀 產品簡述 MS2691 是一款具有 1164MHz ? 1615MHz 全頻段、低功耗的低噪聲放大器芯片。該芯片通過對外圍電路的簡單配置&#xff0c;使得頻帶具有寬帶或窄帶特性。支持不同頻段的各種導…

學習STC51單片機30(芯片為STC89C52RCRC)

每日一言 當你感到疲憊時&#xff0c;正是成長的關鍵時刻&#xff0c;再堅持一下。 IIC協議 是的&#xff0c;IIC協議就是與我們之前的串口通信協議是同一個性質&#xff0c;就是為了滿足模塊的通信&#xff0c;其實之前的串口通信協議叫做UART協議&#xff0c;我們千萬不要弄…

python打卡day47@浙大疏錦行

昨天代碼中注意力熱圖的部分順移至今天 知識點回顧&#xff1a; 熱力圖 作業&#xff1a;對比不同卷積層熱圖可視化的結果 以下是不同卷積層特征圖可視化的對比實現&#xff1a; import torch import matplotlib.pyplot as pltdef compare_conv_layers(model, input_tensor):# …

藍橋杯單片機之通過實現同一個按鍵的短按與長按功能

實現按鍵的短按與長按的不同功能 問題分析 對于按鍵短按&#xff0c;通常是松開后實現其功能&#xff0c;而不會出現按下就進行后續的操作&#xff1b;而對于按鍵長按&#xff0c;則不太一樣&#xff0c;按鍵長按可能分為兩種情況&#xff0c;一是長按n秒后實現后續功能&…

數據導入技術(文檔加載)

1. 簡單文本的讀取 用LangChain讀入txt文檔 # 讀取單個txt文件 import os from langchain_community.document_loaders import TextLoader # 獲取當前腳本文件所在的目錄 script_dir os.path.dirname(__file__) print(f"獲取當前腳本文件所在的目錄&#xff1a;{script…

靶場(二十)---靶場體會小白心得 ---jacko

老樣子開局先看端口&#xff0c;先看http端口 PORT STATE SERVICE VERSION 80/tcp open http Microsoft IIS httpd 10.0 |_http-title: H2 Database Engine (redirect) | http-methods: |_ Potentially risky methods: TRACE |_http-server-header:…

讓AI看見世界:MCP協議與服務器的工作原理

讓AI看見世界&#xff1a;MCP協議與服務器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一種創新的通信協議&#xff0c;旨在讓大型語言模型能夠安全、高效地與外部資源進行交互。在AI技術快速發展的今天&#xff0c;MCP正成為連接AI與現實世界的重要橋梁。…

|從零開始的Pyside2界面編程| 用Pyside2打造一個AI助手界面

&#x1f411; |從零開始的Pyside2界面編程| 用Pyside2打造一個AI助手界面 &#x1f411; 文章目錄 &#x1f411; |從零開始的Pyside2界面編程| 用Pyside2打造一個AI助手界面 &#x1f411;?前言??調取Deepseek大模型??準備工作??調用API? ?將模型嵌入到ui界面中??…

如何利用Elastic Stack(ELK)進行安全日志分析

在以下文章中&#xff0c;我將解釋如何使用Elastic Stack&#xff08;ELK&#xff09;進行安全日志分析&#xff0c;以提高安全性和監控網絡活動。ELK是一個功能強大的開源日志管理和分析平臺&#xff0c;由Elasticsearch、Logstash和Kibana組成&#xff0c;適用于各種用例&…

網絡安全-等級保護(等保)3-0 等級保護測評要求現行技術標準

################################################################################ 第三章&#xff1a;測評要求、測評機構要求&#xff0c;最終目的是通過測評&#xff0c;所以我們將等保要求和測評相關要求一一對應形成表格。 GB/T 28448-2019 《信息安全技術 網絡安全等…

網絡通訊知識——通訊分層介紹,gRPC,RabbitMQ分層

網絡通訊分層 網絡通訊分層是為了將復雜的網絡通信問題分解為多個獨立、可管理的層次&#xff0c;每個層次專注于特定功能。目前主流的分層模型包括OSI七層模型和TCP/IP四層&#xff08;或五層&#xff09;模型&#xff0c;以下是詳細解析&#xff1a; 一、OSI七層模型&#…

gopool 源碼分析

gopool gopool是字節跳動開源節流的gopkg包中協程池的一個實現。 關鍵結構 協程池&#xff1a; type pool struct {// The name of the poolname string// capacity of the pool, the maximum number of goroutines that are actually working// 協程池的最大容量cap int32…

【工作記錄】接口功能測試總結

如何對1個接口進行接口測試 一、單接口功能測試 1、接口文檔信息 理解接口文檔的內容&#xff1a; 請求URL: https://[ip]:[port]/xxxserviceValidation 請求方法: POST 請求參數: serviceCode(必填), servicePsw(必填) 響應參數: status, token 2、編寫測試用例 2.1 正…

Linux中su與sudo命令的區別:權限管理的關鍵差異解析

&#x1f49d;&#x1f49d;&#x1f49d;歡迎蒞臨我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦&#xff1a;「storms…

樂觀鎖與悲觀鎖的實現和應用

樂觀鎖與悲觀鎖&#xff1a;原理、實現與應用詳解 在并發編程和數據庫操作中&#xff0c;樂觀鎖和悲觀鎖是兩種重要的并發控制策略&#xff0c;它們在原理、實現方式和應用場景上存在顯著差異。下面我們將通過圖文結合的方式&#xff0c;深入探討這兩種鎖機制。 一、基本概念 1…

ios蘋果系統,js 滑動屏幕、錨定無效

現象&#xff1a;window.addEventListener監聽touch無效&#xff0c;劃不動屏幕&#xff0c;但是代碼邏輯都有執行到。 scrollIntoView也無效。 原因&#xff1a;這是因為 iOS 的觸摸事件處理機制和 touch-action: none 的設置有關。ios有太多得交互動作&#xff0c;從而會影響…

Redis主從復制原理二 之 主從復制工作流程

概述 本文緊接「Redis主從復制的原理一 之 概述」&#xff0c;詳細介紹了Redis的主從服務過程及原理。 主從復制工作流程 主從復制過程大體可以分為3個階段&#xff1a; 建立連接階段&#xff08;即準備階段&#xff09;數據同步階段命令傳播階段 階段一&#xff1a;建立連接階…

Markdown基礎(1.2w字)

1. Markdown基礎 這次就沒目錄了&#xff0c;因為md格式太亂了寫示例&#xff0c;展示那些都太亂了&#xff0c;導致目錄很亂。 &#xff08;我是XX&#xff0c;出現了很多錯誤&#xff0c;有錯誤和我說&#xff09; 1.1 Markdown簡介 Markdown是一種輕量級的標記語言&#…

JAVA-springboot log日志

SpringBoot從入門到精通-第8章 日志的操作 一、Spring Boot默認的日志框架 SpringBoot支持很多種日志框架&#xff0c;通常情況下&#xff0c;這些日志框架都是由一個日志抽象層和一個日志實現層搭建而成的&#xff0c;日志抽象層是為記錄日志提供的一套標準且規范的框架&…

Vue 渲染 Markdown 文件完全指南

前言 大家好&#xff0c;我是一諾&#xff0c;今天分享的是vue中渲染markdown文件。這是一個常見的需求&#xff0c;比如用戶隱私協議頁、技術說明等文檔頁面~ 本文將詳細介紹如何在 Vue 中渲染 Markdown 文件&#xff0c;并美化代碼塊的顯示效果。 基礎概念 什么是 Markdo…