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

Vue2異步更新及nextTick原理詳解

 更新時(shí)間:2023年04月10日 08:13:25   作者:柏成  
Vue2的異步更新機(jī)制是基于JavaScript的事件循環(huán)機(jī)制實(shí)現(xiàn)的。nextTick方法則是在DOM更新后執(zhí)行回調(diào)函數(shù)。本文詳細(xì)介紹了Vue2的異步更新機(jī)制和nextTick原理,對于理解Vue2的渲染機(jī)制和優(yōu)化性能有很大的幫助。

vue 官網(wǎng)中是這樣描述 nextTick 的

在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個(gè)方法,可以獲取更新后的 DOM。

在學(xué)習(xí) nextTick 是如何實(shí)現(xiàn)之前,我們要先了解下 JavaScript 的執(zhí)行機(jī)制

JavaScript 執(zhí)行機(jī)制

瀏覽器是多線程的,例如GUI渲染線程、JS引擎線程、事件監(jiān)聽線程等。。。

javascript 執(zhí)行機(jī)制就是借用瀏覽器的多線程機(jī)制,再基于 Event Loop 事件循環(huán)機(jī)制實(shí)現(xiàn)的。其實(shí)現(xiàn)了單線程異步效果

Event Loop 步驟大致如下:

瀏覽器加載頁面時(shí),除了開辟堆棧內(nèi)存外,還會(huì)創(chuàng)建兩個(gè)隊(duì)列 Web API:任務(wù)監(jiān)聽隊(duì)列,監(jiān)測異步任務(wù)是否可以執(zhí)行 Task Queue:任務(wù)隊(duì)列,分為異步宏任務(wù)隊(duì)列和異步微任務(wù)隊(duì)列 當(dāng)主線程自上而下執(zhí)行代碼過程中,如果遇到異步代碼,則把異步任務(wù)放到 Web API 中去監(jiān)聽 瀏覽器會(huì)開辟新的線程去監(jiān)聽是否可以執(zhí)行 不會(huì)阻礙主線程的渲染,它會(huì)繼續(xù)向下執(zhí)行同步代碼 當(dāng)異步任務(wù)被監(jiān)測為可以執(zhí)行了(有了運(yùn)行結(jié)果),也不會(huì)立即去執(zhí)行,而是在 task queue 中放置一個(gè)事件,排隊(duì)等待執(zhí)行 根據(jù)微任務(wù)還是宏任務(wù),放在不同的隊(duì)列中 誰先進(jìn)來排隊(duì)的,誰在各自隊(duì)伍的最前面 執(zhí)行棧中的所有同步任務(wù)執(zhí)行完畢,主線程空閑下來,此時(shí)會(huì)去 task queue 中把正在排隊(duì)的事件,按照順序取出來,進(jìn)入主線程執(zhí)行 微任務(wù)優(yōu)先級(jí)比較高。當(dāng)執(zhí)行棧為空時(shí),先去執(zhí)行微任務(wù)隊(duì)列中的事件,直到微任務(wù)隊(duì)列為空,才會(huì)去執(zhí)行宏任務(wù)隊(duì)列中的事件 上述過程會(huì)不斷重復(fù),也就是常說的事件循環(huán)(Event Loop)

task 又分為宏任務(wù)(macro task)和微任務(wù)(micro task)兩大類,在瀏覽器環(huán)境中

常見的 macro task 有 script(整體代碼)、setTimeout/setInterval/setImmediate、XMLHttpRequest/fetch,DOM事件(如鼠標(biāo)點(diǎn)擊、滾動(dòng)頁面、放大縮小等),渲染事件(解析 DOM、計(jì)算布局、繪制) 常見的 micro task 有 Promise.then/catch/finally、async/awaitMutationObserver

需要注意的是?。。∪绻幚砦⑷蝿?wù)的過程中有新的微任務(wù)添加進(jìn)來了,添加的速度一直比執(zhí)行快,則永遠(yuǎn)執(zhí)行微任務(wù)

下面的代碼永遠(yuǎn)不會(huì)打印宏任務(wù)輸出

function macroFn(){
   setTimeout(() => {
     console.log('>>>>MA')
   },0)
}
function microFn(){
    Promise.resolve().then(() => {
        console.log('mi')
        microFn()
    })
}
macroFn()
microFn()

nextTick實(shí)現(xiàn)原理

vue2.7 源碼中,有一個(gè)單獨(dú)的文件src/core/util/next-tick.js去維護(hù) nextTick,有興趣的同學(xué)可以自行去觀看

vue2.7 源碼中,nextTick并沒有直接使用某個(gè) API ,而是采用了優(yōu)雅降級(jí)的方案去實(shí)現(xiàn)異步更新

在內(nèi)部會(huì)嘗試使用原生的Promise.then (IE不支持)、MutationObserversetImmediate (高版本IE專享),如果執(zhí)行環(huán)境還不支持的話,則會(huì)采用 setTimeout(fn, 0)

需要注意的是,我們維護(hù)了一個(gè) callbacks,用于存儲(chǔ) nextTick 回調(diào)

這樣就保證了在同一個(gè) tick 內(nèi)多次調(diào)用 nextTick,只需創(chuàng)建一個(gè)異步任務(wù),就可以依次執(zhí)行 callbacks 中的所有 nextTick 回調(diào)。而不是去開啟多個(gè)異步任務(wù)去處理。

let callbacks = [] // 存儲(chǔ) nextTick 回調(diào)
let waiting = false // 防抖

// 按照順序依次執(zhí)行 callbacks 中的方法
function flushCallbacks() {
  let cbs = callbacks.slice(0)
  waiting = false
  callbacks = []
  cbs.forEach(cb => cb()) 
}


let timerFunc;
if (Promise) {
    timerFunc = () => {
        Promise.resolve().then(flushCallbacks)
    }
}else if(MutationObserver){
    let observer = new MutationObserver(flushCallbacks); // 這里傳入的回調(diào)是異步執(zhí)行的
    let textNode = document.createTextNode(1);
    observer.observe(textNode,{
        characterData:true
    });
    timerFunc = () => {
        textNode.textContent = 2;
    }
}else if(setImmediate){
    timerFunc = () => {
       setImmediate(flushCallbacks);
    }
}else{
    timerFunc = () => {
        setTimeout(flushCallbacks);
     }
}

export function nextTick(cb) {
  callbacks.push(cb) // 維護(hù) nextTick 中的 cakllback 方法
  
  if (!waiting) {
    timerFunc()
    waiting = true
  }
}

異步更新

vue 內(nèi)部的異步更新渲染也使用了 nextTick

在 Watcher 類的 update 更新方法中,我們調(diào)用了 queueWatcher 異步隊(duì)列更新方法,該方法在 vue2.7源碼中的 src/core/util/scheduler.js 文件中維護(hù)

import { queueWatcher } from './scheduler'

class Watcher {
	...
  // 重新渲染
  update() {
    console.log('watcher-update')
    queueWatcher(this) // watcher 異步更新
  }
}

src/core/util/scheduler.js

import { nextTick } from '../util/next-tick'

/**
 * @name QueueWatcher,內(nèi)部 watcher 異步更新
 * @decs 把當(dāng)前的 watcher 暫存起來,在一個(gè)tick周期內(nèi),不管我們的 update 執(zhí)行多少次,只會(huì)執(zhí)行一輪刷新操作
 */

let queue = []
let has = {}
let pending = false // 防抖

function flushSchedulerQueue() {
  let flushQueue = queue.slice(0)
  queue = []
  has = {}
  pending = false
  flushQueue.forEach(q => q.run()) // 在刷新的過程中可能還有新的 watcher,重新放到 queue 中
}

// 在一個(gè)tick周期內(nèi),不管我們的 update 執(zhí)行多少次,只會(huì)執(zhí)行一輪刷新操作
export function queueWatcher(watcher) {
  const id = watcher.id
  if (!has[id]) {
    queue.push(watcher)
    has[id] = true
    if (!pending) {
      nextTick(flushSchedulerQueue)
      pending = true
    }
  }
}

常見問題

1. nexTick 是異步還是同步?

這個(gè)不能一概而論,nextTick 內(nèi)部既有同步代碼又有異步代碼。

例如 維護(hù) callbacks 隊(duì)列是同步任務(wù);執(zhí)行隊(duì)列中的方法是異步任務(wù)

2. nextTick 回調(diào)的執(zhí)行是微任務(wù)還是宏任務(wù)?

針對 vue2.7 來說,nextTick并沒有直接使用某個(gè) API ,而是采用了優(yōu)雅降級(jí)的方案去實(shí)現(xiàn)異步更新。
在內(nèi)部會(huì)嘗試使用原生的Promise.then (微任務(wù))、MutationObserver (微任務(wù))setImmediate (宏任務(wù)),如果執(zhí)行環(huán)境還不支持的話,則會(huì)采用 setTimeout (宏任務(wù))

可以理解為 99% 的場景下都是微任務(wù),只有在不支持 Promise 和 MutationObserver API的瀏覽器中,才會(huì)是宏任務(wù),例如 IE9 、IE10

3. 為什么要封裝 nextTick?而不是使用某個(gè)具體的 API?

優(yōu)雅降級(jí)。盡量使用微任務(wù),盡可能縮短渲染周期

保證統(tǒng)一性。nextTick 可以暴露給用戶,保證用戶在修改數(shù)據(jù)之后立即使用這個(gè)方法,可以獲取更新后的 DOM

this.name = 'libc'

this.$nextTick(()=>{
  console.log(document.querySelector('.user').innerHTML)
});

總結(jié):

Vue2的異步更新機(jī)制是Vue的核心之一,通過事件循環(huán)機(jī)制實(shí)現(xiàn)了高效的渲染和性能優(yōu)化。nextTick方法則提供了更為靈活的DOM操作方式,可以在DOM更新后執(zhí)行回調(diào)函數(shù)。在使用Vue2進(jìn)行開發(fā)時(shí),理解和掌握異步更新機(jī)制和nextTick方法是非常必要的,可以幫助我們更好地優(yōu)化性能和提高渲染效率。

到此這篇關(guān)于Vue2異步更新及nextTick原理詳解的文章就介紹到這了,更多相關(guān)Vue2異步更新及nextTick原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vite配置文件如何加載深入剖析

    Vite配置文件如何加載深入剖析

    我們知道,Vite?構(gòu)建環(huán)境分為開發(fā)環(huán)境和生產(chǎn)環(huán)境,不同環(huán)境會(huì)有不同的構(gòu)建策略,但不管是哪種環(huán)境,Vite?都會(huì)首先解析用戶配置,那接下來,本文就來與大家分析配置解析過程中?Vite?到底做了什么?即Vite是如何加載配置文件的
    2023-11-11
  • 如何用vite打包解決前端發(fā)版后瀏覽器緩存問題

    如何用vite打包解決前端發(fā)版后瀏覽器緩存問題

    這篇文章主要介紹了如何用vite打包解決前端發(fā)版后瀏覽器緩存問題的相關(guān)資料,這樣的配置能夠有效避免瀏覽器緩存問題,確保瀏覽器每次都能加載最新的代碼,同時(shí)又不影響第三方庫的緩存效果,需要的朋友可以參考下
    2024-11-11
  • 詳解Vue中子組件修改父組件傳過來的值的三種方式

    詳解Vue中子組件修改父組件傳過來的值的三種方式

    這篇文章主要為大家詳細(xì)介紹了Vue中子組件修改父組件傳過來的值的三種方式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下
    2024-12-12
  • vuex?store?緩存存儲(chǔ)原理分析

    vuex?store?緩存存儲(chǔ)原理分析

    這篇文章主要介紹了vuex?store?緩存存儲(chǔ)原理,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • vue中組件之間相互傳值的6種方法小結(jié)

    vue中組件之間相互傳值的6種方法小結(jié)

    Vue.js?中組件間通信的方法有很多種,這篇文章主要為大家詳細(xì)介紹了6種常見的直接或間接的組件傳值方式,有需要的小伙伴可以參考一下
    2024-01-01
  • vue百度地圖 + 定位的詳解

    vue百度地圖 + 定位的詳解

    這篇文章主要介紹了vue百度地圖 + 定位的詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Vue router錯(cuò)誤跳轉(zhuǎn)到首頁("/")的問題及解決

    Vue router錯(cuò)誤跳轉(zhuǎn)到首頁("/")的問題及解決

    這篇文章主要介紹了Vue router錯(cuò)誤跳轉(zhuǎn)到首頁("/")的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue echarts封裝組件需求分析與實(shí)現(xiàn)

    Vue echarts封裝組件需求分析與實(shí)現(xiàn)

    在平常的項(xiàng)目中,echarts圖表我們也是使用的非常多的,通常我們從后端拿到數(shù)據(jù),需要在圖表上動(dòng)態(tài)的進(jìn)行呈現(xiàn),接下來我們就模擬從后端獲取數(shù)據(jù)然后進(jìn)行呈現(xiàn)的方法,這篇文章主要介紹了Vue echarts封裝組件需求分析與實(shí)現(xiàn)
    2022-10-10
  • 詳解vue大文件視頻切片上傳的處理方法

    詳解vue大文件視頻切片上傳的處理方法

    前端上傳大文件、視頻的時(shí)候會(huì)出現(xiàn)超時(shí)、過大、很慢等情況,為了解決這一問題,跟后端配合做了一個(gè)切片的功能,接下來就詳細(xì)的給大家介紹一下vue大文件視頻切片上傳的處理方法,需要的朋友可以參考下
    2023-08-08
  • vue使用xlsx導(dǎo)入到表格中示例代碼

    vue使用xlsx導(dǎo)入到表格中示例代碼

    這篇文章主要介紹了vue使用xlsx導(dǎo)入到表格中代碼,具體實(shí)現(xiàn)是先通過FileReader將上傳的文件讀取為二進(jìn)制數(shù)據(jù),然后使用xlsx將它解析成JSON數(shù)據(jù),最后將JSON數(shù)據(jù)填充到表格中,需要的朋友可以參考下
    2023-11-11

最新評論

玉门市| 仁化县| 永昌县| 罗城| 阿瓦提县| 门源| 五华县| 浦江县| 辽中县| 黔西县| 上杭县| 彭阳县| 遂溪县| 渭源县| 延安市| 客服| 长海县| 宁河县| 濉溪县| 滕州市| 嘉禾县| 普格县| 渑池县| 西畴县| 台北市| 日土县| 丰原市| 盈江县| 贵溪市| 晋州市| 资源县| 罗源县| 铁力市| 广安市| 营口市| 资兴市| 涟水县| 隆昌县| 和政县| 宁乡县| 沿河|