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

一文帶你重溫Vue中異步更新隊列的使用場景和場景誤區(qū)

 更新時間:2026年03月09日 08:47:37   作者:拉不動的豬  
在Vue開發(fā)中,明明同步修改了data中的多個變量,視圖卻不會實時同步更新,這問題的根源都指向Vue核心性能優(yōu)化特性——異步更新隊列,下面我們就來看看它的使用場景和場景誤區(qū)吧

在Vue開發(fā)中,明明同步修改了data中的多個變量,視圖卻不會實時同步更新;循環(huán)中多次修改同一個數(shù)據(jù),視圖只顯示最后一次賦值結(jié)果;不同時機觸發(fā)的數(shù)據(jù)更新,偶爾會出現(xiàn)視圖混亂的情況。這些問題的根源,都指向Vue核心性能優(yōu)化特性——異步更新隊列(Async Update Queue) 。

一、為什么Vue要做異步更新隊列

在深入技術(shù)細(xì)節(jié)前,我們先明確一個核心前提:Vue中數(shù)據(jù)的修改是同步的,但DOM的更新是異步的。這不是設(shè)計缺陷,而是Vue為提升性能做出的關(guān)鍵優(yōu)化。

DOM操作是瀏覽器中性能消耗較大的操作之一。如果每次修改data中的數(shù)據(jù),Vue都立即觸發(fā)DOM更新,那么在一個同步函數(shù)中多次修改數(shù)據(jù)(比如循環(huán)修改、連續(xù)賦值),就會觸發(fā)多次DOM重渲染,嚴(yán)重影響頁面性能。

舉個簡單的例子: 如果在一個函數(shù)中連續(xù)修改3個變量,若沒有異步更新隊列,Vue會觸發(fā)3次DOM更新;而有了異步更新隊列,Vue會收集所有數(shù)據(jù)變更,只觸發(fā)1次DOM批量更新,極大減少了性能開銷。

因此,Vue異步更新隊列的核心目的是:通過“批量收集更新任務(wù)、異步批量執(zhí)行”,避免頻繁DOM操作,提升應(yīng)用性能。

二、底層原理:異步更新隊列的執(zhí)行流程

Vue的異步更新隊列,本質(zhì)是基于JavaScript的事件循環(huán)(Event Loop)微任務(wù)(Microtask) 實現(xiàn)的,結(jié)合響應(yīng)式系統(tǒng)的“依賴收集與派發(fā)更新”,形成了完整的執(zhí)行邏輯。具體流程可分為4步:

1. 數(shù)據(jù)變更,觸發(fā)依賴派發(fā)

當(dāng)我們通過this修改data中的響應(yīng)式數(shù)據(jù)時(如this.num = 1),Vue的響應(yīng)式攔截器(Vue2用Object.defineProperty,Vue3用Proxy)會檢測到數(shù)據(jù)變化,進而觸發(fā)“依賴派發(fā)”——通知所有依賴該數(shù)據(jù)的Watcher(Vue2)或Effect(Vue3),準(zhǔn)備執(zhí)行更新。

2. 收集更新任務(wù),加入隊列并去重

派發(fā)更新時,Vue不會立即執(zhí)行DOM更新,而是將“更新DOM”的任務(wù)推入一個專門的更新隊列中。同時,Vue會對隊列進行去重優(yōu)化:如果同一同步階段內(nèi),對同一個數(shù)據(jù)進行多次修改,隊列中只會保留最后一次的更新任務(wù)。

比如:this.num = 1; this.num = 2; this.num = 3; 這三次賦值,隊列中只會保留“將num對應(yīng)的DOM更新為3”的任務(wù),避免無效的DOM操作。

3. 等待同步代碼執(zhí)行完畢

更新隊列不會立即執(zhí)行,而是等待當(dāng)前同步代碼塊(同一事件循環(huán)的同步階段)全部執(zhí)行完畢。也就是說,無論同步函數(shù)中修改多少次數(shù)據(jù),都要等函數(shù)執(zhí)行結(jié)束后,才會處理隊列中的更新任務(wù)。

4. 執(zhí)行隊列,批量更新DOM

同步代碼執(zhí)行完畢后,Vue會從更新隊列中取出所有任務(wù),批量執(zhí)行DOM更新操作,最終只觸發(fā)一次頁面重渲染。值得注意的是,Vue會將更新任務(wù)包裝成微任務(wù)(優(yōu)先于setTimeout等宏任務(wù)執(zhí)行),確保DOM更新的及時性。

補充:Vue2與Vue3的實現(xiàn)差異(核心邏輯一致)

雖然Vue2和Vue3的底層攔截方式不同,但異步更新隊列的核心邏輯完全一致,僅實現(xiàn)細(xì)節(jié)有差異:

  • Vue2:基于Object.defineProperty攔截數(shù)據(jù),更新隊列由Watcher管理,微任務(wù)通過Promise.then、MutationObserver實現(xiàn)(降級為setTimeout);
  • Vue3:基于Proxy攔截數(shù)據(jù),更新隊列由Effect(副作用)管理,微任務(wù)邏輯與Vue2一致,性能更優(yōu)(支持?jǐn)?shù)組、對象新增屬性的響應(yīng)式)。

三、場景舉例

案例1:多變量同步修改,DOM批量更新

場景:一個函數(shù)中同步修改3個變量,這3個變量均在模板中展示,觀察視圖更新情況。

<template>
  <div class="demo">
    <div>變量1:{{ num1 }}</div>
    <div>變量2:{{ num2 }}</div>
    <div>變量3:{{ num3 }}</div>
    <button @click="updateMultiVars">同步修改3個變量</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      num1: 0,
      num2: 0,
      num3: 0
    };
  },
  methods: {
    updateMultiVars() {
      // 同步修改3個變量
      this.num1 = 1;
      this.num2 = 2;
      this.num3 = 3;
      
      // 同步代碼中打印數(shù)據(jù)(同步修改,立即生效)
      console.log("同步代碼中的num1:", this.num1); // 1
      console.log("同步代碼中的num2:", this.num2); // 2
      console.log("同步代碼中的num3:", this.num3); // 3
      
      // 等待DOM更新完成后,打印DOM中的內(nèi)容
      this.$nextTick(() => {
        const doms = document.querySelectorAll('.demo div');
        console.log("DOM中的變量1:", doms[0].innerText); // 變量1:1
        console.log("DOM中的變量2:", doms[1].innerText); // 變量2:2
        console.log("DOM中的變量3:", doms[2].innerText); // 變量3:3
      });
    }
  }
};
</script>

分析:

  • 同步代碼中,num1、num2、num3的修改是即時生效的(控制臺打印結(jié)果為1、2、3),說明數(shù)據(jù)修改是同步的;
  • DOM更新是在updateMultiVars函數(shù)執(zhí)行完畢后批量進行的,通過$nextTick才能獲取到更新后的DOM;
  • 視圖不會出現(xiàn)“先顯示1、0、0,再顯示1、2、0”的中間狀態(tài),而是一次性顯示最終結(jié)果,體現(xiàn)了批量更新的特性。

案例2:循環(huán)修改+即時修改,只保留最后一次賦值

場景:循環(huán)中多次修改同一個變量,同時在同一同步階段修改另一個變量,觀察兩個變量的更新結(jié)果。

<template>
  <div class="demo">
    <div>循環(huán)變量:{{ loopNum }}</div>
    <div>即時變量:{{ instantNum }}</div>
    <button @click="triggerMixedUpdate">循環(huán)+即時修改</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      loopNum: 0,
      instantNum: 0
    };
  },
  methods: {
    triggerMixedUpdate() {
      // 1. 循環(huán)修改loopNum(10次賦值)
      for (let i = 1; i <= 10; i++) {
        this.loopNum = i;
        console.log("循環(huán)中l(wèi)oopNum:", this.loopNum); // 依次打印1-10
      }
      
      // 2. 同一同步階段,即時修改instantNum
      this.instantNum = 100;
      console.log("即時修改后instantNum:", this.instantNum); // 100
      
      // 等待DOM更新完成
      this.$nextTick(() => {
        console.log("DOM中的loopNum:", document.querySelector('.demo div:first-child').innerText); // 循環(huán)變量:10
        console.log("DOM中的instantNum:", document.querySelector('.demo div:last-child').innerText); // 即時變量:100
      });
    }
  }
};
</script>

分析:

  • 循環(huán)中10次修改loopNum,同步代碼中打印的是每次賦值的結(jié)果(1-10),但DOM最終只顯示最后一次賦值(10)——這就是更新隊列的去重優(yōu)化;
  • loopNum的10次更新任務(wù)被合并為1次(更新為10),與instantNum的更新任務(wù)一起,在同步代碼執(zhí)行完畢后批量更新DOM;
  • 核心結(jié)論:同一同步階段,對同一個數(shù)據(jù)的多次修改,只會保留最后一次結(jié)果;不同數(shù)據(jù)的修改,會被一起批量更新

案例3:特殊需求:需要展示數(shù)據(jù)中間狀態(tài)

場景:有時我們需要讓用戶看到數(shù)據(jù)的中間變化(比如num從1→2→3的漸變效果),此時需要打破“同一同步階段批量更新”的規(guī)則,將多次賦值拆分到不同的事件循環(huán)中。

<template>
  <div>漸變數(shù)值:{{ num }}</div>
  <button @click="showMiddleValue">展示中間狀態(tài)</button>
</template>

<script>
export default {
  data() {
    return { num: 0 };
  },
  methods: {
    async showMiddleValue() {
      // 拆分到不同事件循環(huán),每次賦值后等待DOM更新
      this.num = 1;
      await this.$nextTick(); // 等待第一次DOM更新(顯示1)
      
      this.num = 2;
      await this.$nextTick(); // 等待第二次DOM更新(顯示2)
      
      this.num = 3;
      // 最終顯示3
    }
  }
};
</script>

分析:通過await $nextTick(),將每次賦值拆分到不同的微任務(wù)中,打破了同一同步階段的限制,讓Vue每次賦值都觸發(fā)一次DOM更新,從而展示中間狀態(tài)。

四、常見誤區(qū)

誤區(qū)1:數(shù)據(jù)同步 vs DOM異步的區(qū)別(最易混淆)

很多開發(fā)者會混淆“數(shù)據(jù)更新”和“DOM更新”的時機,誤以為“數(shù)據(jù)修改后,視圖會立即同步”,這是最常見的認(rèn)知偏差。

核心區(qū)別:

  • 數(shù)據(jù)更新:同步執(zhí)行,修改this.xxx后,數(shù)據(jù)立即生效(可以在同步代碼中獲取到最新值);
  • DOM更新:異步執(zhí)行,數(shù)據(jù)修改后,DOM不會立即更新,需等待當(dāng)前同步代碼執(zhí)行完畢,由Vue批量更新。

關(guān)鍵突破:判斷數(shù)據(jù)是否修改,直接打印this.xxx即可;判斷DOM是否更新,必須通過$nextTick回調(diào)獲取。

誤區(qū)2:更新隊列的“去重”邏輯

更新隊列的去重邏輯,是“同一同步階段只保留最后一次賦值”的核心原因,也是Vue性能優(yōu)化的關(guān)鍵。

深層解析:

  • 去重的對象:同一數(shù)據(jù)的多次更新任務(wù)(比如多次修改this.num);
  • 去重的時機:更新任務(wù)加入隊列時,Vue會檢查隊列中是否已有該數(shù)據(jù)的更新任務(wù),若有則覆蓋,若無則新增;
  • 去重的目的:避免對同一個DOM節(jié)點進行多次修改,減少DOM操作開銷。

注意:不同數(shù)據(jù)的更新任務(wù)不會被去重(比如同時修改this.num和this.name),會一起被批量執(zhí)行。

誤區(qū)3:$nextTick的作用與使用場景

$nextTick是異步更新隊列的配套API,也是開發(fā)中解決DOM更新時機問題的核心工具,很多開發(fā)者會誤用或忽略它。

核心作用:將回調(diào)函數(shù)延遲到“本次DOM更新完成后”執(zhí)行,本質(zhì)是向微任務(wù)隊列中添加回調(diào),確保能獲取到更新后的DOM。

高頻使用場景:

  • 修改數(shù)據(jù)后,需要立即操作更新后的DOM(比如獲取DOM高度、設(shè)置DOM樣式);
  • 需要等待前一次數(shù)據(jù)更新的DOM完成后,再執(zhí)行下一次數(shù)據(jù)更新(比如案例3中的中間狀態(tài)展示);
  • 在created鉤子中操作DOM(created鉤子中DOM未渲染,需通過$nextTick等待DOM渲染完成)。

注意:$nextTick的回調(diào)是微任務(wù),優(yōu)先于setTimeout等宏任務(wù)執(zhí)行,若需延遲執(zhí)行,可在回調(diào)中嵌套setTimeout。

五、日常開發(fā)中的坑點

坑點1:修改數(shù)據(jù)后,立即操作DOM導(dǎo)致獲取不到最新值

錯誤示例:

updateNum() {
  this.num = 1;
  // 錯誤:此時DOM未更新,獲取到的是舊值
  const domText = document.querySelector('.num').innerText;
  console.log(domText); // 0(舊值)
}

避坑方案:使用$nextTick包裹DOM操作,等待DOM更新完成。

updateNum() {
  this.num = 1;
  this.$nextTick(() => {
    const domText = document.querySelector('.num').innerText;
    console.log(domText); // 1(最新值)
  });
}

閉坑點2:循環(huán)中頻繁修改數(shù)據(jù),導(dǎo)致性能損耗

錯誤示例:循環(huán)1000次,每次修改this.list.push(i),雖然最終只會批量更新DOM,但中間會觸發(fā)1000次依賴派發(fā)和隊列檢查,產(chǎn)生不必要的性能損耗。

badLoop() {
  for (let i = 0; i < 1000; i++) {
    this.list.push(i); // 觸發(fā)1000次依賴派發(fā)
  }
}

避坑方案:先修改本地臨時變量,再一次性賦值給data中的響應(yīng)式變量,只觸發(fā)1次依賴派發(fā)和隊列更新。

goodLoop() {
  const tempList = [];
  for (let i = 0; i < 1000; i++) {
    tempList.push(i); // 本地操作,不觸發(fā)響應(yīng)式
  }
  this.list = tempList; // 一次性賦值,只觸發(fā)1次更新
}

閉坑點3:誤以為$nextTick能“等待下一次數(shù)據(jù)更新”

錯誤認(rèn)知:認(rèn)為nextTick可以等待“后續(xù)修改的數(shù)據(jù)”更新DOM,其實nextTick可以等待“后續(xù)修改的數(shù)據(jù)”更新DOM,其實nextTick可以等待后續(xù)修改的數(shù)據(jù)更新DOM,其實nextTick只能等待“當(dāng)前同步階段”的數(shù)據(jù)更新完成。

錯誤示例:

wrongUse() {
  this.$nextTick(() => {
    // 錯誤:$nextTick回調(diào)中修改的數(shù)據(jù),屬于下一個同步階段,不會被本次$nextTick等待
    this.num = 1;
    console.log(document.querySelector('.num').innerText); // 0(舊值)
  });
}

避坑方案:nextTick只負(fù)責(zé)等待“它被調(diào)用前”的數(shù)據(jù)更新,若在回調(diào)中修改數(shù)據(jù),需再次使用nextTick只負(fù)責(zé)等待“它被調(diào)用前”的數(shù)據(jù)更新,若在回調(diào)中修改數(shù)據(jù),需再次使用nextTick只負(fù)責(zé)等待它被調(diào)用前的數(shù)據(jù)更新,若在回調(diào)中修改數(shù)據(jù),需再次使用nextTick。

correctUse() {
  this.$nextTick(() => {
    this.num = 1;
    this.$nextTick(() => {
      console.log(document.querySelector('.num').innerText); // 1(最新值)
    });
  });
}

閉坑點4:多個異步操作修改數(shù)據(jù),導(dǎo)致視圖混亂

場景:setTimeout回調(diào)和點擊事件同時修改同一個數(shù)據(jù),由于異步操作的執(zhí)行順序不確定,可能導(dǎo)致視圖顯示異常。

錯誤示例:

mounted() {
  // 1. 300ms后修改num為2
  setTimeout(() => {
    this.num = 2;
  }, 300);
},
methods: {
  // 2. 點擊按鈕修改num為1
  handleClick() {
    this.num = 1;
  }
}

問題:若用戶在300ms內(nèi)點擊按鈕,num先被改為1,300ms后又被改為2,視圖會突然變化;若用戶300ms后點擊,num先被改為2,再被改為1,邏輯混亂。

避坑方案:通過“狀態(tài)標(biāo)記”控制異步操作的執(zhí)行順序,避免數(shù)據(jù)被無序修改。

data() {
  return {
    num: 0,
    isClicked: false // 狀態(tài)標(biāo)記
  };
},
mounted() {
  setTimeout(() => {
    // 若用戶未點擊,才修改num為2
    if (!this.isClicked) {
      this.num = 2;
    }
  }, 300);
},
methods: {
  handleClick() {
    this.isClicked = true;
    this.num = 1;
  }
}

閉坑點5:Vue3中Proxy攔截數(shù)組,循環(huán)修改仍需注意批量更新

Vue3用Proxy實現(xiàn)響應(yīng)式,支持?jǐn)?shù)組的原生方法(push、pop等)的響應(yīng)式,但循環(huán)中多次修改數(shù)組元素,仍會被去重優(yōu)化,只保留最后一次結(jié)果。

示例:

// Vue3中
data() {
  return { arr: [1, 2, 3] };
},
methods: {
  updateArr() {
    for (let i = 0; i < 3; i++) {
      this.arr[0] = i; // 多次修改數(shù)組第一個元素
    }
    console.log(this.arr[0]); // 2(最后一次賦值)
  }
}

避坑方案:若需修改數(shù)組多個元素,優(yōu)先使用map、filter等方法生成新數(shù)組,再一次性賦值,避免循環(huán)中多次修改同一元素。

六、異步更新隊列總結(jié)

  • 核心特性:數(shù)據(jù)修改同步,DOM更新異步;同一同步階段,同一數(shù)據(jù)多次修改只保留最后一次,不同數(shù)據(jù)批量更新;
  • 底層依賴:JavaScript事件循環(huán)(微任務(wù)),Vue2基于Object.defineProperty,Vue3基于Proxy;
  • 核心API:$nextTick,用于等待DOM更新完成,解決DOM操作時機問題;
  • 日常開發(fā)優(yōu)化:避免循環(huán)中頻繁修改數(shù)據(jù),合理使用$nextTick,通過狀態(tài)標(biāo)記控制異步操作順序,避開常見閉坑點。

以上就是一文帶你重溫Vue中異步更新隊列的使用場景和場景誤區(qū)的詳細(xì)內(nèi)容,更多關(guān)于Vue異步更新隊列的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • ejsExcel模板在Vue.js項目中的實際運用

    ejsExcel模板在Vue.js項目中的實際運用

    這篇文章主要介紹了ejsExcel模板在Vue.js項目中的實際運用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 解決Vite打包后直接使用瀏覽器打開,顯示空白問題

    解決Vite打包后直接使用瀏覽器打開,顯示空白問題

    這篇文章主要介紹了解決Vite打包后直接使用瀏覽器打開,顯示空白問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Vue3使用contenteditable打造定制化輸入

    Vue3使用contenteditable打造定制化輸入

    contenteditable 屬性為網(wǎng)頁開發(fā)者提供了一種靈活的方式來創(chuàng)建可編輯的內(nèi)容區(qū)域,使用戶可以直接在網(wǎng)頁上進行內(nèi)容編輯,而無需依賴傳統(tǒng)的輸入框,本文將利用contenteditable打造定制化輸入,感興趣的可以了解下
    2023-12-12
  • vue打包部署到springboot的實現(xiàn)示例

    vue打包部署到springboot的實現(xiàn)示例

    項目開發(fā)中,一般我們都會使用SpringBoot+Vue進行前后端開發(fā),本文主要介紹了vue打包部署到springboot的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • el?autocomplete支持分頁上拉加載使用詳解

    el?autocomplete支持分頁上拉加載使用詳解

    這篇文章主要為大家介紹了el?autocomplete支持分頁上拉加載使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • vue3.0如何修改瀏覽器標(biāo)題(靜態(tài))

    vue3.0如何修改瀏覽器標(biāo)題(靜態(tài))

    這篇文章主要介紹了vue3.0如何修改瀏覽器標(biāo)題(靜態(tài)),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vite+vue3+tsx項目打包后動態(tài)路由無法加載頁面的問題及解決

    vite+vue3+tsx項目打包后動態(tài)路由無法加載頁面的問題及解決

    這篇文章主要介紹了vite+vue3+tsx項目打包后動態(tài)路由無法加載頁面的問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 如何解決ElementPlus的el-table底白線問題

    如何解決ElementPlus的el-table底白線問題

    這篇文章主要介紹了如何解決ElementPlus的el-table底白線問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • vue-element-admin登錄攔截設(shè)置白名單方式

    vue-element-admin登錄攔截設(shè)置白名單方式

    這篇文章主要介紹了vue-element-admin登錄攔截設(shè)置白名單方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Vue/React/Angular渲染失效原因解析與修復(fù)指南

    Vue/React/Angular渲染失效原因解析與修復(fù)指南

    在Vue、React和Angular中,為什么數(shù)據(jù)變了界面卻不動,每個框架的常見失效場景有哪些,我們又該如何診斷和修復(fù),下面小編就來和大家簡單聊聊吧
    2025-08-08

最新評論

泰和县| 西宁市| 阳新县| 眉山市| 五家渠市| 彰武县| 阿克苏市| 盐边县| 阳新县| 波密县| 东宁县| 玉屏| 平顶山市| 桦南县| 沅江市| 扶沟县| 锦州市| 昌宁县| 古浪县| 惠安县| 郁南县| 东莞市| 淄博市| 印江| 明星| 阿拉尔市| 南漳县| 玛曲县| 宜昌市| 宜阳县| 瑞丽市| 清新县| 内黄县| 花莲市| 集贤县| 读书| 景谷| 偃师市| 莱州市| 民县| 张家港市|