偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

揭秘!Vue3.5響應(yīng)式重構(gòu)如何讓內(nèi)存占用減少56%

開發(fā) 前端
Vue3.5響應(yīng)式重構(gòu)主要是通過雙向鏈表和版本計(jì)數(shù)?實(shí)現(xiàn)的,優(yōu)化后內(nèi)存占用減少了56%。主要原因是:在新的響應(yīng)式系統(tǒng)中多了一個(gè)Link節(jié)點(diǎn)?用于鏈接Sub訂閱者和Dep依賴?,更新Sub訂閱者依賴只是進(jìn)行指針的變換,并且還能夠復(fù)用Link節(jié)點(diǎn)?以及將不再使用的Link節(jié)點(diǎn)給孤立出來便于V8更快的將這個(gè)Link節(jié)點(diǎn)給回收。

前言

Vue3.5版本又將響應(yīng)式給重構(gòu)了,重構(gòu)后的響應(yīng)式系統(tǒng)主要有兩部分組成:雙向鏈表和 版本計(jì)數(shù)。我們?cè)谇皟善恼轮形覀円呀?jīng)講過了 雙向鏈表和 版本計(jì)數(shù),這篇文章我們來講講為什么這次重構(gòu)能夠讓內(nèi)存占用減少56%。

為什么說“又”將響應(yīng)式重構(gòu)了

因?yàn)樵谥暗腣ue3.4版本中剛剛將響應(yīng)式給重構(gòu)了,這次響應(yīng)式重構(gòu)是vscode插件Vue-Official(原名Volar)的作者Johnson Chu搞的。

3.4版本的重構(gòu)優(yōu)化了很多東西,最直觀的就是:computed計(jì)算屬性的值沒有變化,另外一個(gè)watch又監(jiān)聽了這個(gè)computed的值。在3.4以前還是會(huì)觸發(fā)watch的回調(diào),經(jīng)過3.4的優(yōu)化后就不會(huì)觸發(fā)了。

在3.5版本以前,Vue的響應(yīng)式系統(tǒng)中有兩個(gè)角色:Sub訂閱者和Dep依賴。

Sub訂閱者:主要有watchEffect、watch、render函數(shù)、computed等。

Dep依賴:主要有ref、reactive、computed等響應(yīng)式變量。

他們兩之間是相互依賴的關(guān)系,如下圖:

圖片圖片

Dep依賴(比如ref響應(yīng)式變量)可以通過dep屬性訪問到Sub訂閱者(比如computed計(jì)算屬性),就知道了到底有哪些訂閱者依賴自己,當(dāng)自己的值改變后就能去通知訂閱者。

同樣Sub訂閱者(比如computed計(jì)算屬性)可以通過deps屬性訪問到Dep依賴(比如ref響應(yīng)式變量),當(dāng)Sub訂閱者不再依賴某個(gè)變量時(shí)就可以通過這個(gè)關(guān)系去訪問到這個(gè)Dep依賴。然后把自己從不再依賴的變量的Sub訂閱者集合中去掉,這樣當(dāng)這個(gè)響應(yīng)式變量改變后就不會(huì)通知到不再訂閱到他的Sub訂閱者了。

我們來看個(gè)例子,代碼如下:

<template>
  <p>{{ doubleCount }}</p>
  <button @click="flag = !flag">切換flag</button>
</template>

<script setup>
import { computed, ref } from "vue";
const count1 = ref(1);
const count2 = ref(10);
const flag = ref(true);

const doubleCount = computed(() => {
  console.log("computed");
  if (flag.value) {
    return count1.value * 2;
  } else {
    return count2.value * 2;
  }
});
</script>

當(dāng)flag的值為true時(shí)計(jì)算屬性doubleCount其實(shí)只依賴響應(yīng)式變量flag和count1,當(dāng)flag的值切換為false時(shí),計(jì)算屬性應(yīng)該變成依賴變量flag和count2。

就上面這個(gè)更新Sub訂閱者依賴的邏輯,Vue其實(shí)重構(gòu)了很多次。在早期的Vue3版本中是直接清空Sub訂閱者所依賴的響應(yīng)式變量,然后再重新執(zhí)行計(jì)算屬性doubleCount時(shí)再去將新的響應(yīng)式變量進(jìn)行收集。很明顯這個(gè)版本內(nèi)存的使用就非常浪費(fèi)了。

在最新的Vue3.4版本重構(gòu)后的響應(yīng)式系統(tǒng)中會(huì)在執(zhí)行計(jì)算屬性之前利用_trackId和_depsLength字段進(jìn)行標(biāo)記,在重新執(zhí)行計(jì)算屬性時(shí)進(jìn)行依賴收集就可以利用_trackId和_depsLength字段判斷出Dep依賴是否能夠復(fù)用,并且執(zhí)行完計(jì)算屬性的回調(diào)函數(shù)后同樣利用_trackId和_depsLength字段就可以將不再依賴的Dep依賴給移除掉。

上面這個(gè)方案看著很完美,但是他的核心是依賴計(jì)算屬性中所依賴的變量順序不變,如果順序變了,那么依然還是不能夠復(fù)用的,同樣會(huì)對(duì)浪費(fèi)內(nèi)存。(PS:這一段3.4版本響應(yīng)式看不懂沒關(guān)系,因?yàn)樗呀?jīng)是過去式了)

內(nèi)存優(yōu)化主要原因:復(fù)用Link節(jié)點(diǎn)

在Vue3.5版本中那個(gè)最了解Vue的男人出手了,使用雙向鏈表和版本計(jì)數(shù)將響應(yīng)式系統(tǒng)再次給重構(gòu)了。說實(shí)話這次重構(gòu)后讓讀響應(yīng)式源碼的門檻變得更高了,但是收益特別明顯,最主要是通過復(fù)用Link節(jié)點(diǎn)去實(shí)現(xiàn)減少內(nèi)存的使用。

還是上面的那個(gè)例子,對(duì)應(yīng)新的響應(yīng)式模型如下圖:

圖片圖片

在新的響應(yīng)式模型中Sub訂閱者和Dep依賴之間不再有直接的關(guān)聯(lián)關(guān)系了,而是通過中間的Link節(jié)點(diǎn)作為橋梁去關(guān)聯(lián)。

在前一節(jié)中我們講過了,3.5以前Sub訂閱者中有屬性會(huì)去存依賴的Dep依賴,Dep依賴中有屬性去存依賴他的Sub訂閱者,所以導(dǎo)致當(dāng)Sub訂閱者依賴的變量需要更新時(shí)就無(wú)法做到完全的復(fù)用,內(nèi)存就會(huì)浪費(fèi)。

如果下面的內(nèi)容你看不懂,這不是你理解力有問題,原因是你對(duì)雙向鏈表不熟悉,可以先看看我之前的 雙向鏈表文章。

在3.5新的響應(yīng)式模型中,X軸是Dep依賴,Y軸是Sub訂閱者,Link節(jié)點(diǎn)是作為坐標(biāo)軸上面的點(diǎn)。每一組Dep依賴和Sub訂閱者都會(huì)對(duì)應(yīng)一個(gè)Link節(jié)點(diǎn),并且可以通過這個(gè)Link節(jié)點(diǎn)直接訪問到Dep依賴和Sub訂閱者。

在Y軸上面找一個(gè)點(diǎn)(比如Sub1也就是計(jì)算屬性doubleCount),橫向出發(fā)就可以找到Sub1訂閱者所依賴的所有響應(yīng)式變量。因?yàn)闄M向的這些Link節(jié)點(diǎn)是一個(gè)雙向鏈表,并且可以通過某一個(gè)Link節(jié)點(diǎn)直接訪問到他的Dep依賴。

當(dāng)flag的值切換為false后,訂閱者Sub1所依賴的響應(yīng)式變量就從flag+count1變成flag+count2。這時(shí)我們需要做的事情就很簡(jiǎn)單了,新建一個(gè)Link3節(jié)點(diǎn),可以直接訪問到Sub1和Dep3。然后將Link1中原本指向Link2的指針改為指向Link3,同時(shí)讓Link3的指針也指向Link1。并且將Link2指向Link1的指針改為指向空,由于Dep2現(xiàn)在不被任何訂閱者所依賴了,所以將Link2原本指向Dep2的指針也改為指向空,同樣將Dep2指向Link2的指針也指向空。

上面的一頓操作,除了必要的初始化一個(gè)Link3之外我們一直都是在進(jìn)行指針的操作,并不像以前的響應(yīng)式一樣去增加Sub訂閱者依賴或者減少依賴,這是非常高效的方式。

當(dāng)flag的值切換為false后,新的響應(yīng)式模型圖如下:

圖片圖片

從上圖中可以看到Link2已經(jīng)徹底從雙向鏈表中移除了,并且整個(gè)過程中我們都是在操作指針的指向,所以Link1也一直都是復(fù)用的。

V8在進(jìn)行垃圾回收的時(shí)候發(fā)現(xiàn)Link2不再被任何變量所使用,就可以認(rèn)為L(zhǎng)ink2是一個(gè)可以被回收的變量,就會(huì)將其直接回收釋放內(nèi)存。

Link節(jié)點(diǎn)復(fù)用以及讓不再使用的Link節(jié)點(diǎn)盡快的被回收進(jìn)而釋放內(nèi)存,就是這次響應(yīng)式重構(gòu)減少56%內(nèi)存占用的主要原因。

其他優(yōu)化

有了雙向鏈表后依賴觸發(fā)也變得更加清晰了,當(dāng)某個(gè)響應(yīng)式變量改變后,只需要遍歷Dep依賴(縱向)的Link節(jié)點(diǎn)組成的雙向鏈表,然后通過這些Link節(jié)點(diǎn)直接訪問到對(duì)應(yīng)的Sub訂閱者,觸發(fā)其依賴。

基于此Sub訂閱者的觸發(fā)就是一個(gè)線性的過程,所以就可以實(shí)現(xiàn)將需要觸發(fā)的Sub訂閱者串起來組成了一個(gè)Sub訂閱者組成的隊(duì)列。等需要觸發(fā)的訂閱者收集完了后,再去進(jìn)行觸發(fā)Sub訂閱者,避免同一個(gè)訂閱者被觸發(fā)多次。

依賴觸發(fā)相比之前也變得更加簡(jiǎn)單了,性能以及內(nèi)存也有所提升。

最后就是因?yàn)橛辛穗p向鏈表和版本計(jì)數(shù)的加持后,computed計(jì)算屬性變得更加聰明,現(xiàn)在是惰性計(jì)算了。computed計(jì)算屬性只有等有人使用他(比如在template中使用計(jì)算屬性doubleCount)后才會(huì)去執(zhí)行計(jì)算屬性中的回調(diào)函數(shù),以及3.4版本中就已經(jīng)實(shí)現(xiàn)的如果計(jì)算屬性值沒有變化,另外一個(gè)watch又監(jiān)聽了這個(gè)computed的值,此時(shí)這個(gè)watch不會(huì)被觸發(fā)。關(guān)于這個(gè)可以看我之前的版本計(jì)數(shù)文章。

總結(jié)

Vue3.5響應(yīng)式重構(gòu)主要是通過雙向鏈表和版本計(jì)數(shù)實(shí)現(xiàn)的,優(yōu)化后內(nèi)存占用減少了56%。主要原因是:在新的響應(yīng)式系統(tǒng)中多了一個(gè)Link節(jié)點(diǎn)用于鏈接Sub訂閱者和Dep依賴,更新Sub訂閱者依賴只是進(jìn)行指針的變換,并且還能夠復(fù)用Link節(jié)點(diǎn)以及將不再使用的Link節(jié)點(diǎn)給孤立出來便于V8更快的將這個(gè)Link節(jié)點(diǎn)給回收。此外還有Sub訂閱者的觸發(fā)也變得更加簡(jiǎn)單,以及現(xiàn)在是computed計(jì)算屬性是惰性計(jì)算了,這些優(yōu)化同樣也優(yōu)化了內(nèi)存的使用。

責(zé)任編輯:武曉燕 來源: 前端歐陽(yáng)
相關(guān)推薦

2024-11-06 10:47:53

2024-10-14 12:56:28

2024-09-04 11:42:17

Vue3.5源碼API

2024-09-02 08:48:45

2025-05-15 08:10:00

Vue 3.5Vue

2025-05-29 01:55:00

Vue3.5API性能

2024-09-05 09:17:14

2024-07-11 09:00:13

2010-10-28 15:15:08

oracle內(nèi)存參數(shù)

2025-02-17 08:58:06

2020-07-14 08:32:49

VuelocalStorag響應(yīng)式

2011-08-17 10:53:16

Firefox 7

2020-06-09 11:35:30

Vue 3響應(yīng)式前端

2019-07-01 13:34:22

vue系統(tǒng)數(shù)據(jù)

2021-01-22 11:47:27

Vue.js響應(yīng)式代碼

2025-07-03 09:36:35

2021-03-12 19:26:54

ChromeChrome瀏覽器瀏覽器

2023-12-06 07:43:56

Vue如何定義事件

2021-05-19 14:25:19

前端開發(fā)技術(shù)

2017-08-30 17:10:43

前端JavascriptVue.js
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)