最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析vue中$nextTick的作用與原理

 更新時間:2023年10月20日 14:05:24   作者:前端技術(shù)棧  
這篇文章主要為大家詳細(xì)介紹一下Vue中$nextTick的作用于原理,這也是面試中常常考到的問題,文中的示例代碼講解詳細(xì),對我們深入了解Vue有一定的幫助,需要的小伙伴可以參考一下

一、為什么使用nextTick

因為 vue 采用的異步更新策略,當(dāng)監(jiān)聽到數(shù)據(jù)發(fā)生變化的時候不會立即去更新DOM,

而是開啟一個任務(wù)隊列,并緩存在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更;

這種做法帶來的好處就是可以將多次數(shù)據(jù)更新合并成一次,減少操作DOM的次數(shù),

如果不采用這種方法,假設(shè)數(shù)據(jù)改變100次就要去更新100次DOM,而頻繁的DOM更新是很耗性能的。

二、nextTick 作用

nextTick 接收一個回調(diào)函數(shù)作為參數(shù),并將這個回調(diào)函數(shù)延遲到DOM更新后才執(zhí)行;

使用場景:想要操作 基于最新數(shù)據(jù)生成的DOM 時,就將這個操作放在 nextTick 的回調(diào)中;

下面是一個簡單示例,展示了如何使用nextTick:

new Vue({
  data() {
    return {
      message: 'Hello, Vue!'
    }
  },
  mounted() {
    this.message = 'Modified message'
    this.$nextTick(() => {
      // 在DOM更新之后執(zhí)行的操作
      console.log(this.$el.textContent) // 輸出:"Modified message"
    })
  }
})
 

代碼解析:

第一次 console.log 的時候,獲取的到的是舊值,這是因為 value 數(shù)據(jù)發(fā)生變化的時候,Vue 沒有立刻去更新 DOM ,而是將修改數(shù)據(jù)的操作放在了一個異步操作隊列中,如果一直修改相同數(shù)據(jù),異步操作隊列還會進行去重,等待同一事件循環(huán)中的所有數(shù)據(jù)變化完成之后,會將隊列中的事件拿來進行處理,進行 DOM 的更新
第二次的 console.log 是放到 this.$nextTick 回調(diào)函數(shù)中的,此時獲取到的是新值,是因為 nextTick 的回調(diào)函數(shù)是在 DOM 更新之后觸發(fā)的

三、nextTick 原理

將傳入的回調(diào)函數(shù)包裝成異步任務(wù),異步任務(wù)又分微任務(wù)和宏任務(wù),為了盡快執(zhí)行所以優(yōu)先選擇微任務(wù);

nextTick 提供了四種異步方法 Promise.then、MutationObserver、setImmediate、setTimeout(fn,0)

源碼解讀

源碼位置 core/util/next-tick

源碼并不復(fù)雜,三個函數(shù),60幾行代碼,沉下心去看!

Tips:為了便于理解我調(diào)整了源碼中 nextTick、timerFunc、flushCallbacks 三個函數(shù)的書寫順序

import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'
 
//  上面三行與核心代碼關(guān)系不大,了解即可
//  noop 表示一個無操作空函數(shù),用作函數(shù)默認(rèn)值,防止傳入 undefined 導(dǎo)致報錯
//  handleError 錯誤處理函數(shù)
//  isIE, isIOS, isNative 環(huán)境判斷函數(shù),
//  isNative 判斷某個屬性或方法是否原生支持,如果不支持或通過第三方實現(xiàn)支持都會返回 false
 
 
export let isUsingMicroTask = false     // 標(biāo)記 nextTick 最終是否以微任務(wù)執(zhí)行
 
const callbacks = []     // 存放調(diào)用 nextTick 時傳入的回調(diào)函數(shù)
let pending = false     // 標(biāo)記是否已經(jīng)向任務(wù)隊列中添加了一個任務(wù),如果已經(jīng)添加了就不能再添加了
    // 當(dāng)向任務(wù)隊列中添加了任務(wù)時,將 pending 置為 true,當(dāng)任務(wù)被執(zhí)行時將 pending 置為 false
    // 
 
 
// 聲明 nextTick 函數(shù),接收一個回調(diào)函數(shù)和一個執(zhí)行上下文作為參數(shù)
// 回調(diào)的 this 自動綁定到調(diào)用它的實例上
export function nextTick(cb?: Function, ctx?: Object) {
    let _resolve
    // 將傳入的回調(diào)函數(shù)存放到數(shù)組中,后面會遍歷執(zhí)行其中的回調(diào)
    callbacks.push(() => {
        if (cb) {   // 對傳入的回調(diào)進行 try catch 錯誤捕獲
            try {
                cb.call(ctx)
            } catch (e) {    // 進行統(tǒng)一的錯誤處理
                handleError(e, ctx, 'nextTick')
            }
        } else if (_resolve) {
            _resolve(ctx)
        }
    })
    
    // 如果當(dāng)前沒有在 pending 的回調(diào),
    // 就執(zhí)行 timeFunc 函數(shù)選擇當(dāng)前環(huán)境優(yōu)先支持的異步方法
    if (!pending) {
        pending = true
        timerFunc()
    }
    
    // 如果沒有傳入回調(diào),并且當(dāng)前環(huán)境支持 promise,就返回一個 promise
    // 在返回的這個 promise.then 中 DOM 已經(jīng)更新好了,
    if (!cb && typeof Promise !== 'undefined') {
        return new Promise(resolve => {
            _resolve = resolve
        })
    }
}
 
 
// 判斷當(dāng)前環(huán)境優(yōu)先支持的異步方法,優(yōu)先選擇微任務(wù)
// 優(yōu)先級:Promise---> MutationObserver---> setImmediate---> setTimeout
// setTimeout 可能產(chǎn)生一個 4ms 的延遲,而 setImmediate 會在主線程執(zhí)行完后立刻執(zhí)行
// setImmediate 在 IE10 和 node 中支持
 
// 當(dāng)在同一輪事件循環(huán)中多次調(diào)用 nextTick 時 ,timerFunc 只會執(zhí)行一次
 
let timerFunc   
// 判斷當(dāng)前環(huán)境是否原生支持 promise
if (typeof Promise !== 'undefined' && isNative(Promise)) {  // 支持 promise
    const p = Promise.resolve()
    timerFunc = () => {
       // 用 promise.then 把 flushCallbacks 函數(shù)包裹成一個異步微任務(wù)
        p.then(flushCallbacks)
        if (isIOS) setTimeout(noop)
        // 這里的 setTimeout 是用來強制刷新微任務(wù)隊列的
        // 因為在 ios 下 promise.then 后面沒有宏任務(wù)的話,微任務(wù)隊列不會刷新
    }
    // 標(biāo)記當(dāng)前 nextTick 使用的微任務(wù)
    isUsingMicroTask = true
    
    
    // 如果不支持 promise,就判斷是否支持 MutationObserver
    // 不是IE環(huán)境,并且原生支持 MutationObserver,那也是一個微任務(wù)
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
    isNative(MutationObserver) ||
    MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
    let counter = 1
    // new 一個 MutationObserver 類
    const observer = new MutationObserver(flushCallbacks) 
    // 創(chuàng)建一個文本節(jié)點
    const textNode = document.createTextNode(String(counter))   
    // 監(jiān)聽這個文本節(jié)點,當(dāng)數(shù)據(jù)發(fā)生變化就執(zhí)行 flushCallbacks 
    observer.observe(textNode, { characterData: true })
    timerFunc = () => {
        counter = (counter + 1) % 2
        textNode.data = String(counter)  // 數(shù)據(jù)更新
    }
    isUsingMicroTask = true    // 標(biāo)記當(dāng)前 nextTick 使用的微任務(wù)
    
    
    // 判斷當(dāng)前環(huán)境是否原生支持 setImmediate
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
    timerFunc = () => { setImmediate(flushCallbacks)  }
} else {
 
    // 以上三種都不支持就選擇 setTimeout
    timerFunc = () => { setTimeout(flushCallbacks, 0) }
}
 
 
// 如果多次調(diào)用 nextTick,會依次執(zhí)行上面的方法,將 nextTick 的回調(diào)放在 callbacks 數(shù)組中
// 最后通過 flushCallbacks 函數(shù)遍歷 callbacks 數(shù)組的拷貝并執(zhí)行其中的回調(diào)
function flushCallbacks() {
    pending = false    
    const copies = callbacks.slice(0)    // 拷貝一份 callbacks
    callbacks.length = 0    // 清空 callbacks
    for (let i = 0; i < copies.length; i++) {    // 遍歷執(zhí)行傳入的回調(diào)
        copies[i]()
    }
}
 
// 為什么要拷貝一份 callbacks
 
// 用 callbacks.slice(0) 將 callbacks 拷貝出來一份,
// 是因為考慮到在 nextTick 回調(diào)中可能還會調(diào)用 nextTick 的情況,
// 如果在 nextTick 回調(diào)中又調(diào)用了一次 nextTick,則又會向 callbacks 中添加回調(diào),
// 而 nextTick 回調(diào)中的 nextTick 應(yīng)該放在下一輪執(zhí)行,
// 否則就可能出現(xiàn)一直循環(huán)的情況,
// 所以需要將 callbacks 復(fù)制一份出來然后清空,再遍歷備份列表執(zhí)行回調(diào)

到此這篇關(guān)于淺析vue中$nextTick的作用與原理的文章就介紹到這了,更多相關(guān)vue $nextTick內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue中g(shù)et方法\post方法如何傳遞數(shù)組參數(shù)詳解

    vue中g(shù)et方法\post方法如何傳遞數(shù)組參數(shù)詳解

    在前后端交互的時候,有時候需要通過get或者delete傳遞一個數(shù)組給后臺,下面下面這篇文章主要給大家介紹了關(guān)于vue中g(shù)et方法\post方法如何傳遞數(shù)組參數(shù),文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • vue2引入Three.js預(yù)覽3D文件的實現(xiàn)方法

    vue2引入Three.js預(yù)覽3D文件的實現(xiàn)方法

    three.js是一個基于WebGL的JavaScript庫,它允許開發(fā)者在網(wǎng)頁上創(chuàng)建和顯示3D圖形,這篇文章主要介紹了vue2引入Three.js預(yù)覽3D文件的實現(xiàn)方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-10-10
  • 深入探索VueJS Scoped CSS 實現(xiàn)原理

    深入探索VueJS Scoped CSS 實現(xiàn)原理

    這篇文章主要介紹了深入探索VueJS Scoped CSS 實現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • vue3+element?Plus實現(xiàn)表格前端分頁完整示例

    vue3+element?Plus實現(xiàn)表格前端分頁完整示例

    這篇文章主要給大家介紹了關(guān)于vue3+element?Plus實現(xiàn)表格前端分頁的相關(guān)資料,雖然很多時候后端會把分頁,搜索,排序都做好,但是有些返回數(shù)據(jù)并不多的頁面,或者其他原因不能后端分頁的通常會前端處理,需要的朋友可以參考下
    2023-08-08
  • VUE項目中調(diào)用高德地圖的全流程講解

    VUE項目中調(diào)用高德地圖的全流程講解

    這篇文章主要介紹了VUE項目中調(diào)用高德地圖的全流程講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Vue項目保存代碼之后頁面自動更新問題

    Vue項目保存代碼之后頁面自動更新問題

    這篇文章主要介紹了Vue項目保存代碼之后頁面自動更新問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 解決vue接口數(shù)據(jù)賦值給data沒有反應(yīng)的問題

    解決vue接口數(shù)據(jù)賦值給data沒有反應(yīng)的問題

    今天小編就為大家分享一篇解決vue接口數(shù)據(jù)賦值給data沒有反應(yīng)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • el-date-picker時間清空值為null處理方案

    el-date-picker時間清空值為null處理方案

    本文介紹關(guān)于Vue.js項目中時間選擇器組件的問題,當(dāng)選擇后清空導(dǎo)致值變?yōu)閚ull,進而引發(fā)后臺接口報錯,通過監(jiān)聽`overallForm.time`的值并設(shè)置為空數(shù)組,成功解決此問題,確保了數(shù)據(jù)正確性,同時,建議避免直接監(jiān)聽整個對象以優(yōu)化性能,感興趣的朋友一起看看吧
    2024-08-08
  • Vue 實現(xiàn)高級穿梭框 Transfer 封裝過程

    Vue 實現(xiàn)高級穿梭框 Transfer 封裝過程

    本文介紹了基于Vue2和Element-UI實現(xiàn)的高級穿梭框組件Transfer的設(shè)計與技術(shù)方案,組件支持多項選擇,并能實時同步已選擇項,包含豎版和橫版設(shè)計稿,并提供了組件的使用方法和源碼,此組件具備本地分頁和搜索功能,適用于需要在兩個列表間進行數(shù)據(jù)選擇和同步的場景
    2024-09-09
  • vue組件props屬性監(jiān)聽不到值變化問題

    vue組件props屬性監(jiān)聽不到值變化問題

    這篇文章主要介紹了vue組件props屬性監(jiān)聽不到值變化問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04

最新評論

天全县| 紫阳县| 西和县| 乃东县| 河曲县| 利辛县| 随州市| 张家口市| 蓬莱市| 新余市| 桦甸市| 平凉市| 诏安县| 苍山县| 普定县| 洛扎县| 鲁山县| 斗六市| 治多县| 琼结县| 凤山县| 保亭| 玉龙| 莲花县| 无锡市| 保山市| 丰原市| 赤水市| 保定市| 上虞市| 罗甸县| 班玛县| 中山市| 沽源县| 涡阳县| 新乡县| 板桥市| 宿迁市| 湘潭市| 高雄市| 茶陵县|