一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

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

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

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

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

掃碼添加小助手

加入工程師交流群

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

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

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

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

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

簡化模型

為了更直觀的理解vue依賴收集的模型,我們先來看一個“簡單”的功能描述:

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


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

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

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

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


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ù)這種咋辦?不管!我們只管肯定沒問題的!

我們由此可以確定

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

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


// 當(dāng)前的監(jiān)聽函數(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)聽函數(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類似 ***/
} 

測試一下效果

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

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

看起來達(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)聽函數(shù)的觸發(fā)流程抽離為trigger函數(shù);這樣,我們實(shí)現(xiàn)了一個簡單的依賴收集系統(tǒng)。

Vue依賴收集模型

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

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

1. Proxy對象get監(jiān)聽,set觸發(fā)

Vue3中,Proxy代理數(shù)據(jù)在被讀取時“依賴收集”,在被賦值時會“觸發(fā)依賴”;我們試一下上面完成的依賴收集系統(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;
    }
})

測試一下

測試代碼如下:

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

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

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

看起來效果不錯!但是下面的例子里有問題:

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

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

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

2. “key”級依賴

我們可以將對象的屬性作為基本單位進(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)??吹竭@里,似乎完成的很不錯了,但是看到下面的例子:

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

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

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

3. 分支切換

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

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

審核編輯:黃飛

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

    關(guān)注

    3

    文章

    4381

    瀏覽量

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

    關(guān)注

    0

    文章

    18

    瀏覽量

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

    關(guān)注

    0

    文章

    7

    瀏覽量

    6473

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

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

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

掃碼添加小助手

加入工程師交流群

    評論

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

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

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

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

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

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

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

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

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

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

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

    Vue入門之Vue定義

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

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

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

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

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

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

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

    使用Vue3時遇到的些問題

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

    看懂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 ?1968次閱讀
    <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的對比 ?對TypeScript支持不友好(所有屬性都放在了this對象上,難以推倒組件的數(shù)據(jù)類型) ?大量的API
    的頭像 發(fā)表于 12-20 10:24 ?453次閱讀

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

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