chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文看懂Vue3響應(yīng)式系統(tǒng)原理

馬哥Linux運(yùn)維 ? 來(lái)源:馬哥Linux運(yùn)維 ? 2023-12-07 10:55 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

響應(yīng)式的基本概念

響應(yīng)式是指當(dāng)數(shù)據(jù)發(fā)生變化時(shí),系統(tǒng)會(huì)自動(dòng)更新與數(shù)據(jù)相關(guān)的 DOM 結(jié)構(gòu)。

在 Vue2 中,響應(yīng)式系統(tǒng)的實(shí)現(xiàn)基于Object.defineProperty。然而,Object.defineProperty有一些局限,如:無(wú)法監(jiān)聽(tīng)數(shù)組的變化、需要遍歷對(duì)象的每個(gè)屬性進(jìn)行監(jiān)聽(tīng)、性能開(kāi)銷較大。

在 Vue3 中,響應(yīng)式系統(tǒng)的實(shí)現(xiàn)基于 ES6 的Proxy對(duì)象。Proxy可以直接監(jiān)聽(tīng)對(duì)象和數(shù)組的變化,而無(wú)需對(duì)每個(gè)屬性進(jìn)行監(jiān)聽(tīng),從而大大提高性能。同時(shí),Proxy也可以解決Object.defineProperty無(wú)法監(jiān)聽(tīng)數(shù)組的問(wèn)題。

響應(yīng)式的關(guān)鍵在于vue的依賴收集機(jī)制。

簡(jiǎn)化模型

為了更直觀的理解vue依賴收集的模型,我們先來(lái)看一個(gè)“簡(jiǎn)單”的功能描述:

已知watcher函數(shù),調(diào)用了一些“外部函數(shù)”:


function watcher () {
    console.log('watcher start')
    函數(shù)1(); 
    函數(shù)2();
    console.log('watcher end')
}

能否設(shè)計(jì)一個(gè)依賴收集系統(tǒng),使這些“外部函數(shù)”運(yùn)行時(shí),watcher也會(huì)隨之運(yùn)行?

關(guān)鍵:如何判斷函數(shù)間的調(diào)用關(guān)系?

看似有點(diǎn)難,實(shí)際一點(diǎn)也不簡(jiǎn)單,我們需要知道函數(shù)間調(diào)用關(guān)系。我們先看個(gè)例子:


function A() { console.log('A') }
function B() { console.log('B') }
function C() { console.log('C') }
...


function watcher () {
    console.log('watcher start!')
    /* *這里調(diào)用了上面的某些函數(shù)* */
    console.log('watcher end!')
}
/* *這里運(yùn)行了某些函數(shù)* */
watcher();


- watcher start!
- A
- B
- wathcer end! 
- C

運(yùn)行結(jié)果我們可以看出watcher內(nèi)部一定調(diào)用了A、B函數(shù):

為啥?js是單線程的。

C函數(shù)一定在watcher外面嗎?不一定。例如:

function watcher () { console.log('start') A() B() setTimeout(()=>{ C() }) console.log('end') } watcher();

C函數(shù)這種咋辦?不管!我們只管肯定沒(méi)問(wèn)題的!

我們由此可以確定

函數(shù)watcher執(zhí)行期間,凡是運(yùn)行過(guò)的函數(shù),一定是watcher內(nèi)部調(diào)用過(guò)的函數(shù)

根據(jù)這個(gè)原理,我們?cè)O(shè)計(jì)依賴收集系統(tǒng)如下:


// 當(dāng)前的監(jiān)聽(tīng)函數(shù)
let activeEffect = null
// 副作用函數(shù)
function effect (watcher) {
    activeEffect = watcher
    // watcher執(zhí)行的期間就是依賴收集的階段
    watcher(true)
    activeEffect= null
}
// isTracking:是否是依賴收集階段
function A (isTracking = false) {
    if (isTracking) {
        // 依賴收集階段,effects就是A的監(jiān)聽(tīng)函數(shù)集合
        A.effects = A.effects || new Set()
        A.effects.add(activeEffect)
    } else {
        // 依賴運(yùn)行階段
        console.log('A觸發(fā)了')
        A.effects.forEach(fn => fn(true))
    }
}
function B (isTracking = false) {
    /*** 與A類似 ***/
} 

測(cè)試一下效果

2160c52e-94a1-11ee-939d-92fbcf53809c.png

218bd12e-94a1-11ee-939d-92fbcf53809c.png

看起來(lái)達(dá)到了要求。

將上面代碼優(yōu)化一下,最終如下


let activeEffect = null;
function effect (watcher) {    
    activeEffect = watcher;    
    watcher(true);
    
    activeEffect = null;
}


const bucket = new WeakMap();


function track (target) {
    const effects = bucket.get(target) || new Set();
    activeEffect && effects.add(activeEffect);
    bucket.set(target, effects);
}




function trigger (target) {
    bucket.get(target)?.forEach?.(fn => fn(true));
}
function A (isTracking = false) {
    if (isTracking) {
        
        track(A);
    } else {
        console.log('A觸發(fā)了')
        
        trigger(A);
    }
}
function B (isTracking = false) {
    
}

這里將之前 A.effects = A.effects || new Set();依賴收集流程提取成track函數(shù),監(jiān)聽(tīng)函數(shù)的觸發(fā)流程抽離為trigger函數(shù);這樣,我們實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的依賴收集系統(tǒng)。

Vue依賴收集模型

我們知道Vue3是通過(guò)Proxy實(shí)現(xiàn)的依賴收集流程,Proxy示例:

21b2e732-94a1-11ee-939d-92fbcf53809c.png

1. Proxy對(duì)象get監(jiān)聽(tīng),set觸發(fā)

Vue3中,Proxy代理數(shù)據(jù)在被讀取時(shí)“依賴收集”,在被賦值時(shí)會(huì)“觸發(fā)依賴”;我們?cè)囈幌律厦嫱瓿傻囊蕾囀占到y(tǒng),看下效果:


const data = {
    value: 1,
}
const proxyData = new Proxy(data, {
    get(target, key) {
        
        track(target);
        return target[key];
    },
    set(target, key, value) {
        
        trigger(target);
        target[key] = value;
    }
})

測(cè)試一下

測(cè)試代碼如下:

21b99622-94a1-11ee-939d-92fbcf53809c.png

終端運(yùn)行結(jié)果:

21bed538-94a1-11ee-939d-92fbcf53809c.png

看起來(lái)效果不錯(cuò)!但是下面的例子里有問(wèn)題:

21e2b908-94a1-11ee-939d-92fbcf53809c.png

21e6c7be-94a1-11ee-939d-92fbcf53809c.png

一個(gè)無(wú)關(guān)的屬性key的賦值也會(huì)觸發(fā)監(jiān)聽(tīng)函數(shù)!這不是我們想要的。為了精確監(jiān)聽(tīng),還需要細(xì)化依賴收集系統(tǒng)。

2. “key”級(jí)依賴

我們可以將對(duì)象的屬性作為基本單位進(jìn)行依賴收集。改造如下:


// 依賴收集函數(shù),這里精確到keyfunction track (target, key) {    const effects = bucket.get(target) || new Map();    const keyMap = effects.get(key) || new Set();    effects.set(key, keyMap);    bucket.set(target, effects);    activeEffect && keyMap.add(activeEffect);}// 依賴觸發(fā)函數(shù),這里精確到keyfunction trigger (target, key) {    const effects = bucket.get(target);    if (!effects) return;    const keyMap = effects.get(key);    if (!keyMap) return;    keyMap.forEach(effect => effect());}
const data = {    value: 1}const proxyData = new Proxy(data, {    get(target, key) {
        // 具體到key進(jìn)行收集        track(target, key);        return target[key]    },    set(target, key, value) {
        // 觸發(fā)到key        trigger(target, key);        target[key] = value    }})

這里試一下效果

21f8e12e-94a1-11ee-939d-92fbcf53809c.png

22082b5c-94a1-11ee-939d-92fbcf53809c.png

這樣就實(shí)現(xiàn)了精確到屬性的監(jiān)聽(tīng)系統(tǒng)。看到這里,似乎完成的很不錯(cuò)了,但是看到下面的例子:

2211c0d6-94a1-11ee-939d-92fbcf53809c.png

這里value屬性由false變?yōu)閠rue后,屬性data的就已不再參與監(jiān)聽(tīng)函數(shù)內(nèi)的邏輯了;監(jiān)聽(tīng)函數(shù)不應(yīng)該再響應(yīng)data屬性,但實(shí)際上并沒(méi)有。因?yàn)橐蕾囮P(guān)系已經(jīng)固化,data屬性只要變化就一定會(huì)觸發(fā)監(jiān)聽(tīng),不管是否真的需要:

222b1842-94a1-11ee-939d-92fbcf53809c.png

3. 分支切換

為了優(yōu)化這一點(diǎn),應(yīng)將依賴關(guān)系實(shí)時(shí)更新,將多余的監(jiān)聽(tīng)去除。為此,vue采取的策略是:

每次監(jiān)聽(tīng)函數(shù)運(yùn)行前,都要將自己的依賴關(guān)系清除;然后在運(yùn)行期間重建依賴關(guān)系。(版權(quán)歸掘金硬毛巾原作者所有,侵刪)

審核編輯:黃飛

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4400

    瀏覽量

    66366
  • DOM
    DOM
    +關(guān)注

    關(guān)注

    0

    文章

    18

    瀏覽量

    9796
  • 監(jiān)聽(tīng)系統(tǒng)

    關(guān)注

    0

    文章

    7

    瀏覽量

    6489

原文標(biāo)題:Vue3響應(yīng)式系統(tǒng)原理

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    解析Vue代碼層面的優(yōu)化

    項(xiàng)目首屏優(yōu)化、Webpack 編譯配置優(yōu)化等問(wèn)題,所以我們?nèi)匀恍枰リP(guān)注 Vue 項(xiàng)目性能方面的優(yōu)化,使項(xiàng)目具有更高效的性能、更好的用戶體驗(yàn)。本文是作者通過(guò)實(shí)際項(xiàng)目的優(yōu)化實(shí)踐進(jìn)行總結(jié)而來(lái),希望讀者讀完本文,有定的啟發(fā)思考,從而對(duì)自己的項(xiàng)目進(jìn)行優(yōu)化起到幫助。本文內(nèi)容分為以
    發(fā)表于 10-27 11:39

    基于TypeScript實(shí)現(xiàn)Vue3.0指令組件拖拽

    最近在用vue3重構(gòu)后臺(tái)的個(gè)功能。個(gè)彈窗組件,彈出個(gè)表單。然后點(diǎn)擊提交。早上運(yùn)維突然跑過(guò)來(lái)問(wèn)我,為啥彈窗擋住了下邊的表格的數(shù)據(jù),我添加的時(shí)候,都沒(méi)法對(duì)照表格來(lái)看了。你必須給我解決
    發(fā)表于 11-04 06:58

    Vue框架的教程資料免費(fèi)下載

    Vue套用于構(gòu)建用戶界面的漸進(jìn)JavaScript框架。與其它大型框架不同的是,Vue 被設(shè)計(jì)為可以自底向上逐層應(yīng)用。Vue 的核心庫(kù)
    發(fā)表于 03-18 08:00 ?0次下載
    <b class='flag-5'>Vue</b>框架的教程資料免費(fèi)下載

    關(guān)于vue如何去水印的解決方法的介紹

    很多人都懂些簡(jiǎn)單的電腦系統(tǒng)問(wèn)題的解決方案,但是vue怎么去水印的解決思路卻鮮為人知,小編前幾天就遇到了vue怎么去水印的問(wèn)題,于是準(zhǔn)備整理
    發(fā)表于 03-24 17:33 ?3607次閱讀

    關(guān)于React和Vue產(chǎn)生定的認(rèn)知

    Vue2 相較 Vue3 版本而言牢牢占據(jù)著大部分 Vue 開(kāi)發(fā)者的視野,但是因?yàn)?Vue 官方已經(jīng)把 Vue3 作為默認(rèn)的版本,所以在此同
    的頭像 發(fā)表于 11-02 13:18 ?1207次閱讀

    Vue入門之Vue定義

    Vue (讀音 /vju?/,類似于 view) 是套用于構(gòu)建用戶界面的漸進(jìn)JavaScript框架。 Vue 的核心庫(kù)只關(guān)注視圖層,也就是只處理頁(yè)面。
    的頭像 發(fā)表于 02-06 16:41 ?1506次閱讀
    <b class='flag-5'>Vue</b>入門之<b class='flag-5'>Vue</b>定義

    如何使用springboot+vue搭建個(gè)人網(wǎng)站3

    Vue.js(讀音 /vju?/, 類似于 view)是個(gè)構(gòu)建數(shù)據(jù)驅(qū)動(dòng)的 web 界面的漸進(jìn)框架。Vue現(xiàn)在這么火,大家都懂。接下來(lái)讓我們來(lái)認(rèn)識(shí)
    的頭像 發(fā)表于 02-14 16:05 ?1769次閱讀
    如何使用springboot+<b class='flag-5'>vue</b>搭建個(gè)人網(wǎng)站<b class='flag-5'>3</b>

    搭建基于Vue3+Vite2+Arco+Typescript+Pinia后臺(tái)管理系統(tǒng)模板

    今天我們就來(lái)快速搭建個(gè)基于Vue3+Vite2+Arco+Typescript+Pinia后臺(tái)管理系統(tǒng)模板。這樣可以幫大家快速制作自己的后臺(tái)模板
    的頭像 發(fā)表于 03-01 10:09 ?1291次閱讀
    搭建基于<b class='flag-5'>Vue3</b>+Vite2+Arco+Typescript+Pinia后臺(tái)管理<b class='flag-5'>系統(tǒng)</b>模板

    簡(jiǎn)單介紹Vue中的響應(yīng)原理

    自從 Vue 發(fā)布以來(lái),就受到了廣大開(kāi)發(fā)人員的青睞,提到 Vue,我們首先想到的就是 Vue響應(yīng)
    的頭像 發(fā)表于 03-13 10:11 ?1133次閱讀

    使用Vue3時(shí)遇到的些問(wèn)題

    Vue3 目前已經(jīng)趨于穩(wěn)定,不少代碼庫(kù)都已經(jīng)開(kāi)始使用它,很多項(xiàng)目未來(lái)也必然要遷移至 Vue3。本文記錄我在使用 Vue3 時(shí)遇到的些問(wèn)題,希望能為其他開(kāi)發(fā)者提供幫助。
    的頭像 發(fā)表于 09-13 10:16 ?1497次閱讀
    使用<b class='flag-5'>Vue3</b>時(shí)遇到的<b class='flag-5'>一</b>些問(wèn)題

    看懂FPGA芯片投資框架.zip

    看懂FPGA芯片投資框架
    發(fā)表于 01-13 09:06 ?4次下載

    看懂PCB天線、FPC天線的特性.zip

    看懂PCB天線、FPC天線的特性
    發(fā)表于 03-01 15:37 ?33次下載

    看懂BLE Mesh

    看懂BLE Mesh
    的頭像 發(fā)表于 12-06 16:24 ?2254次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>看懂</b>BLE Mesh

    Vue3設(shè)計(jì)思想及響應(yīng)源碼剖析

    作者:京東物流 喬盼盼 、Vue3結(jié)構(gòu)分析 1、Vue2與Vue3的對(duì)比 ?對(duì)TypeScript支持不友好(所有屬性都放在了this對(duì)象上,難以推倒組件的數(shù)據(jù)類型) ?大量的API
    的頭像 發(fā)表于 12-20 10:24 ?630次閱讀

    看懂電感、磁珠和零歐電阻的區(qū)別

    電子發(fā)燒友網(wǎng)站提供《看懂電感、磁珠和零歐電阻的區(qū)別.docx》資料免費(fèi)下載
    發(fā)表于 01-02 14:48 ?3次下載