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

Vue之關(guān)于異步更新細(xì)節(jié)

 更新時間:2024年06月07日 15:04:13   作者:玉案軒窗  
這篇文章主要介紹了Vue之關(guān)于異步更新細(xì)節(jié),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

前言

Vue官網(wǎng)對于異步更新的介紹如下:

  • Vue 在更新 DOM 時是異步執(zhí)行的。
  • 只要偵聽到數(shù)據(jù)變化,Vue 將開啟一個隊列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。
  • 如果同一個 watcher 被多次觸發(fā),只會被推入到隊列中一次。
  • 這種在緩沖時去除重復(fù)數(shù)據(jù)對于避免不必要的計算和 DOM 操作是非常重要的

Vue使用Object.defineProperty對數(shù)據(jù)劫持后,當(dāng)對對象進(jìn)行set操作,就會觸發(fā)視圖更新。

更新邏輯

以下面實例來分析視圖更新處理邏輯:

<div>{{ message }}</div>
<button @click="handleClick">更新</button>

new Vue({
	data: {
		message: ''
	},
	methods: {
		handleClick() {
			this.message = Date.now();
		}
	}
})

當(dāng)點擊更新按鈕后會對已劫持的屬性message做賦值操作,此時會觸發(fā)Object.defineProperty的set操作。

Object.defineProperty set操作

Object.defineProperty的set函數(shù)的設(shè)置,實際上最核心的邏輯就是觸發(fā)視圖更新,具體代碼邏輯如下:

set: function reactiveSetter (newVal) {
	// 其他邏輯
	
    // 觸發(fā)視圖更新
    dep.notify();
}

每個屬性都會對應(yīng)一個Dep對象,當(dāng)對屬性進(jìn)行賦值時就會調(diào)用Dep的notify實例方法,該實例方法的功能就是是通知視圖需要更新。

Dep notify實例方法

notify實例方法的代碼邏輯如下:

Dep.prototype.notify = function notify () {
  // stabilize the subscriber list first
  var subs = this.subs.slice();
  for (var i = 0, l = subs.length; i < l; i++) {
    subs[i].update();
  }
};

subs中存儲是watcher對象,每個Vue實例都存在一個與視圖更新關(guān)聯(lián)的watcher對象,該對象的創(chuàng)建是在$mount階段,具體看查看之前的文章Vue實例創(chuàng)建整體流程。

代表屬性的Dep對象與watcher對象的關(guān)聯(lián)是在render函數(shù)調(diào)用階段具體屬性獲取時建立的即依賴收集

notify方法會執(zhí)行與當(dāng)前屬性關(guān)聯(lián)的所有watcher對象的update方法,必然會存在一個視圖更新相關(guān)的watcher。

watcher對象的按照分類實際上分為兩類:

  • 視圖更新相關(guān)的,每一個Vue實例都存在一個此類的watcher對象
  • 邏輯計算相關(guān)的,計算屬性和watch監(jiān)聽所創(chuàng)建的watcher對象

Watcher update實例方法

update實例方法的代碼邏輯具體如下:

Watcher.prototype.update = function update () {
  /* istanbul ignore else */
  if (this.lazy) {
    this.dirty = true;
  } else if (this.sync) {
    this.run();
  } else {
    queueWatcher(this);
  }
};

lazy、sync都是Watcher的屬性,分別表示:

  • lazy:表示懶處理,即延遲相關(guān)處理,用于處理計算屬性
  • computedsync:表示同步執(zhí)行,即觸發(fā)屬性更新就立即更新視圖

從上面邏輯中可知,默認(rèn)是queueWatcher處理即開啟一個隊列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更,即視圖是異步更新的。

這里需要注意的一點是:

queueWatcher中必然存在視圖更新的watcher對象,不會存在計算屬性computed對應(yīng)的watcher(computed對應(yīng)的watcher對象lazy屬性默認(rèn)為true),可能存在watch API對應(yīng)的用戶性質(zhì)的watcher對象

queueWatcher執(zhí)行邏輯

function queueWatcher (watcher) {
  var id = watcher.id;
  if (has[id] == null) {
    has[id] = true;
    if (!flushing) {
      queue.push(watcher);
    } else {
      // if already flushing, splice the watcher based on its id
      // if already past its id, it will be run next immediately.
      var i = queue.length - 1;
      while (i > index && queue[i].id > watcher.id) {
        i--;
      }
      queue.splice(i + 1, 0, watcher);
    }
    // queue the flush
    if (!waiting) {
      waiting = true;
      nextTick(flushSchedulerQueue);
    }
  }
}

實際上面邏輯主要分成3點:

  • 對于同一個watcher對象,使用has對象結(jié)構(gòu)+id為key來判斷隊列中是否已存在對應(yīng)watcher對象,如果存在就不會將其添加到queue中
  • 通過flushing標(biāo)識區(qū)分當(dāng)在清空隊列過程中和正常情況下,如何向queue中添加watcher
  • 通過waiting標(biāo)識區(qū)分是否要執(zhí)行nextTick即清空queue的動作

因為queue是全局變量,在此步驟之前就將watcher對象添加到queue,如果waiting為true就標(biāo)識已經(jīng)調(diào)用nextTick實現(xiàn)異步處理queue了,就不要再次調(diào)用nextTick

從上面整體邏輯可知,queueWacther的邏輯主要就兩點:

  • 判斷是否重復(fù)watcher,對于不重復(fù)的watcher將其添加到queue中
  • 調(diào)用nextTick開啟異步處理queue操作即flushSchedulerQueue函數(shù)執(zhí)行

nextTick + flushSchedulerQueue

nextTick函數(shù)實際上跟$nextTick是相同的邏輯,主要的區(qū)別就是上下文的不同,即函數(shù)的this綁定值的不同。

使用macroTask API還是microTask API來執(zhí)行flushSchedulerQueue

而flushSchedulerQueue函數(shù)就是queue的具體處理邏輯,主要邏輯如下:

function flushSchedulerQueue () {
  flushing = true;
  var watcher, id;

  // Sort queue before flush.
  // This ensures that:
  // 1. Components are updated from parent to child. (because parent is always
  //    created before the child)
  // 2. A component's user watchers are run before its render watcher (because
  //    user watchers are created before the render watcher)
  // 3. If a component is destroyed during a parent component's watcher run,
  //    its watchers can be skipped.
  queue.sort(function (a, b) { return a.id - b.id; });

  for (index = 0; index < queue.length; index++) {
    watcher = queue[index];
    id = watcher.id;
    has[id] = null;
    watcher.run();
  }

  var activatedQueue = activatedChildren.slice();
  var updatedQueue = queue.slice();

  resetSchedulerState();

  // call component updated and activated hooks
  callActivatedHooks(activatedQueue);
  callUpdatedHooks(updatedQueue);
}

flushSchedulerQueue函數(shù)的主要邏輯可以總結(jié)成如下幾點:

  • 對隊列queue中watcher對象進(jìn)行排序
  • 遍歷queue執(zhí)行每個watcher對象的run方法
  • 重置控制queue的相關(guān)狀態(tài),用于下一輪更新
  • 執(zhí)行組件的updated和activated生命周期

這里就不展開了,需要注意的是activated是針對于keep-alive下組件的特殊處理,updated生命周期是先子組件再父組件的,隊列queue的watcher對象是按照父組件子組件順序排列的,所以在源碼中updated生命周期的觸發(fā)是倒序遍歷queue觸發(fā)的。

首先說說watcher對象的run實例方法,該方法的主要邏輯就是執(zhí)行watcher對象的getter屬性和cb屬性對應(yīng)的函數(shù)。

上面說過watcher對象的按照分類實際上分為兩類:

  • 視圖更新相關(guān)的,每一個Vue實例都存在一個此類的watcher對象
  • 邏輯計算相關(guān)的,計算屬性和watch監(jiān)聽所創(chuàng)建的watcher對象

watcher對象的getter屬性和cb屬性就是對應(yīng)著上面各類watcher的實際處理邏輯,例如watch API對應(yīng)的getter屬性就是監(jiān)聽項,cb屬性才是具體的處理邏輯。

為什么需要對queue中watcher對象進(jìn)行排序?

實際上Vue源碼中有相關(guān)說明,這主要涉及到嵌套組件Vue實例創(chuàng)建、render watch和用戶watch創(chuàng)建的時機。

每個組件都是一個Vue實例,嵌套組件創(chuàng)建總是從父組件Vue實例開始創(chuàng)建的,在父組件patch階段才創(chuàng)建子組件的Vue實例。

而這個順序決定了watcher對象的id值大小問題:

父組件的所有watcher對象id < 子組件的所有watcher對象id

render watch實際上就是與視圖更新相關(guān)的watcher對象,該對象是其對應(yīng)的Vue實例創(chuàng)建的末期即掛載階段才創(chuàng)建的,是晚于用戶watch即計算屬性computed和watch API創(chuàng)建的watcher對象,所以:

render watch的id < 所有用戶watch的id的

子組件可能是更新觸發(fā)源,如果父組件也需要更新視圖,這樣queue隊列中子組件的watcher對象位置會在父組件的watcher對象之前,對queue中watcher對象進(jìn)行排序就保證了:

視圖更新時 父組件 總是先于 子組件開始更新操作,而每個組件對應(yīng)的視圖渲染的watcher最后再執(zhí)行(即用戶watcher對象對應(yīng)的邏輯先執(zhí)行)

總結(jié)

Vue異步更新的過程還是非常清晰的:

  • 對屬性賦值觸發(fā)Dep對象notify方法執(zhí)行
  • 繼而執(zhí)行Watcher對象的update方法將對象保存到隊列queue中
  • 繼而調(diào)用mircoTask API或macroTask API執(zhí)行queue中任務(wù)
  • 對隊列中watcher進(jìn)行排序,保證順序執(zhí)行的正確性,調(diào)用其對應(yīng)run方法來實現(xiàn)視圖更新和相關(guān)邏輯更新操作

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 關(guān)于vue單文件中引用路徑的處理方法

    關(guān)于vue單文件中引用路徑的處理方法

    這篇文章主要給大家介紹了關(guān)于vue單文件中引用路徑處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用vue.js具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • 淺談Vuex的狀態(tài)管理(全家桶)

    淺談Vuex的狀態(tài)管理(全家桶)

    本篇文章主要介紹了淺談Vuex狀態(tài)管理(全家桶),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • Vue中v-if、v-if-else、v-else-if與v-show的基本使用

    Vue中v-if、v-if-else、v-else-if與v-show的基本使用

    v-if,v-else,v-else-if,v-if指令用于條件性地渲染一塊內(nèi)容,這塊內(nèi)容只會在指令的表達(dá)式返回truth值的時候被渲染,這篇文章主要給大家介紹了關(guān)于Vue中v-if、v-if-else、v-else-if與v-show的基本使用,需要的朋友可以參考下
    2022-10-10
  • 利用Vue實現(xiàn)將圖片轉(zhuǎn)換為Base64編碼的方法

    利用Vue實現(xiàn)將圖片轉(zhuǎn)換為Base64編碼的方法

    這篇文章主要介紹了利用Vue實現(xiàn)將圖片轉(zhuǎn)換為Base64編碼的方法,Base64是一種編碼方式,用于將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成64個基于ASCII的可打印字符,這種編碼可嵌入圖像到HTML或CSS中,減少加載時間,解決跨域問題,并支持離線應(yīng)用開發(fā),需要的朋友可以參考下
    2024-10-10
  • vue element 生成無線級左側(cè)菜單的實現(xiàn)代碼

    vue element 生成無線級左側(cè)菜單的實現(xiàn)代碼

    這篇文章主要介紹了vue element 生成無線級左側(cè)菜單的實現(xiàn)代碼,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08
  • 通過Vue+axios獲取接口數(shù)據(jù)的示例詳解

    通過Vue+axios獲取接口數(shù)據(jù)的示例詳解

    這篇文章主要介紹了Vue結(jié)合axios獲取笑話接口數(shù)據(jù)的示例,重點講解axios的特性、使用方法及請求方式,演示如何通過get方法獲取數(shù)據(jù)并展示,同時解決this指向問題,感興趣的小伙伴跟著小編一起來看看吧
    2025-08-08
  • Vue?和?Django?實現(xiàn)?Token?身份驗證的流程

    Vue?和?Django?實現(xiàn)?Token?身份驗證的流程

    這篇文章主要介紹了Vue?和?Django?實現(xiàn)?Token?身份驗證?,Vue.js?和?Django?編寫的前后端項目中,實現(xiàn)了基于?Token?的身份驗證機制,其他前后端框架的?Token?實現(xiàn)原理與本文一致,需要的朋友可以參考下
    2022-08-08
  • el-tree?loadNode懶加載的實現(xiàn)

    el-tree?loadNode懶加載的實現(xiàn)

    本文主要介紹了el-tree?loadNode懶加載的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 如何在vue3中同時使用tsx與setup語法糖

    如何在vue3中同時使用tsx與setup語法糖

    這篇文章主要介紹了如何在vue3中同時使用tsx與setup語法糖,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • vue中sync語法糖的用法詳解

    vue中sync語法糖的用法詳解

    Vue的.sync語法糖是一個用于雙向數(shù)據(jù)綁定的指令,可以在子組件中用來監(jiān)聽父組件傳遞下來的props的變化,本文給大家介紹了在Vue中,.sync語法糖的使用方法,感興趣的朋友跟著小編一起來學(xué)習(xí)吧
    2024-01-01

最新評論

苏尼特右旗| 涟水县| 乐清市| 兴义市| 班玛县| 冕宁县| 天门市| 高唐县| 横峰县| 台中市| 莎车县| 西安市| 双城市| 潞西市| 尉氏县| 徐州市| 万宁市| 宁津县| 盘锦市| 永善县| 玉龙| 湟中县| 襄垣县| 南康市| 永昌县| 巴林右旗| 玉溪市| 铁岭县| 嘉义市| 海淀区| 禄劝| 缙云县| 柳州市| 洛浦县| 伊宁县| 航空| 固安县| 张掖市| 武汉市| 桐城市| 保定市|