vue3X 和 vue2X響應式原理對比-簡要實現(xiàn)

1. 前言

理解響應式有助于理解代碼邏輯
Vue3 基于proxy
Vue2 基于Object.defineProperty


2. 什么是數(shù)據(jù)響應式

所謂的數(shù)據(jù)響應式就是能夠使數(shù)據(jù)的變化可以被檢測
并對這種變化做出響應的機制

我們常見的MVVM框架中要解決的一個核心問題就是連接數(shù)據(jù)層視圖層,
通過數(shù)據(jù)驅動應用,數(shù)據(jù)變化,視圖更新,
需要對數(shù)據(jù)做響應式處理,這樣一旦數(shù)據(jù)發(fā)生變化就可以立即做出``更新處理`

響應式

數(shù)據(jù)變化可偵測, 從而對使用數(shù)據(jù)的地方進行更新


3.Vue中的應用

通過數(shù)據(jù)響應式 加上虛擬DOMpatch算法,可以使我們只需要操作數(shù)據(jù),完全不用接觸繁瑣的DOM操作,從而大大提升開發(fā)效率,降低開發(fā)難度


4. 簡要對比

4.1 Vue2

基于 Proxy的數(shù)據(jù)響應式 Vue 2的響應式系統(tǒng)使用 Object.definePropertygettersetter杖虾。

Vue2的數(shù)據(jù)響應式會根據(jù)數(shù)據(jù)類型做不同的處理:

對象就采用 Object.defineProperty()的定義方式來攔截數(shù)據(jù),當數(shù)據(jù)被訪問或者發(fā)生變化時,我們感知并作出響應;
數(shù)組則通過覆蓋數(shù)組原型的方法,擴展它的7個變更方法,使這些方法可以額外的做更新通知,從而做出響應

這種機制很好的解決了數(shù)據(jù)響應式的問題,但也存在缺點:

1.比如初始化的時候遞歸遍歷會造成性能損失
2.新增或刪除屬性時需要用戶使用Vue.set/delete這樣的特殊api才能生效
3.對于es6中的Map,Set這些數(shù)據(jù)結構不支持等問題


4.2 Vue3

Vue 3將使用 ES2015 Proxy作為 其觀察機制徊哑,這將會帶來如下變化:

1.組件實例初始化的速度提高 100%
2.使用 Proxy 節(jié)省以前一半的內存開銷弦讽,加快速度,但是存在低瀏覽器版本的不兼容
3.為了繼續(xù)支持IE11涧偷,Vue 3 將發(fā)布一個支持舊觀察者機制和新 Proxy 版本的構建
4.編程體驗是一致的,不需要使用特殊的api


5.Vue2實現(xiàn)數(shù)據(jù)的監(jiān)聽的簡要核心代碼

5.1 簡要代碼

    if(typeof obj !== "object" || obj == null){
        return
    }
    const keys = Object.keys(obj)
    for(let i = 0;i < keys.length;i++){
        const key = keys[i]
        defineReactive(obj,key,obj[key])
    }
    console.log("變了",obj)
}

function defineReactive(obj,key,val){
    observe(obj)
    Object.defineProperty(obj,key,{
        get (){
            return val
        },
        set(v){
            val = v
            update()
        }
    })
}
function update(){
    console.log(obj.yzs)
}
const obj = {}
defineReactive(obj,"yzs","名字")
obj.yzs = "幸福一家人"


5.2 運行

1.可以作為 nodejs來運行
2.也可以在前端頁面引入查看瀏覽器控制臺結果


5.3 分析

1.攔截每個key從而可以偵測數(shù)據(jù)的變化
2.只能對于對象支持比較好 , 數(shù)組的話就得單獨寫
3.遍歷每個key成本高:內存大,速度慢
4.新增或刪除 屬性無法監(jiān)聽 需要使用特殊的API
5.Vue.set(obj,"yzs","幸福一家人")
6.Vue.delete(obj,"幸福一家人")
7.不支持 Map,Set,Class等數(shù)據(jù)結構


6. Vue3響應式簡要代碼

6.1 核心代碼

function  reactive(obj) {
    return new Proxy(obj,{
        get(target,key){
            console.log("get 的key",key);

            return target[key]
        },
        set(target,key,val){
            // notify 通知
            console.log("set 的key",key);

            target[key] = val
        },
        deleteProperty(target,key){
            // notify 通知
            console.log("delete 的key",key);
            delete target[key]
        }
    })
}
const state = reactive({
    name:"yzs"
})
state.yzs
state.yzs = "yzs001"
delete state.yzs
state.age = 31
state.age

6.2 分析

代理整個對象,從而偵測數(shù)據(jù)變化

1.語言級別的支持 對象數(shù)組 都可以監(jiān)聽
2.Proxy原理就是 在對象外面套一層殼,這個殼就是Proxy ,
屬于懶處理 不訪問不進行處理
例如:不恰當?shù)牧凶?Vue2就是全員檢測 Vue3就是只針對出門的進行檢測
3.es6的proxy數(shù)據(jù)響應式,很好的解決了以上問題

4.上面的代碼其實只能檢測到 單層對象對象里面嵌套的話檢測不到,我把代碼貼到下邊,有興趣的可以看看


7. 嵌套對象監(jiān)聽

//代理整個對象,從而偵測數(shù)據(jù)變化

function  reactive(obj) {
    return new Proxy(obj,{
        get(target,key){
            console.log("get 的key",key);

            // 依賴手機
            track(target,key)
            return  typeof target[key] === "object"
             ?  reactive(target[key])
             :  target[key]
        },
        set(target,key,val){
            // notify 通知
            console.log("set 的key",key);
            trigger(target,key)
            target[key] = val
        },
        deleteProperty(target,key){
            // notify 通知
            console.log("delete 的key",key);
            delete target[key]
        }
    })
}

// 臨時存儲副作用函數(shù)
const effectStack = []
// 1. 依賴 收集函數(shù)
// 包裝 fn
// 立即執(zhí)行 fn
// 返回 fn
function effect(fn) {
    const e = createReactiveEffect(fn)
    e()
    return e
}
function createReactiveEffect(fn) {
    const effect = function () {
        try {
            effectStack.push(fn)
            return fn()  
        } 
        catch (error) {
            
        } finally{
            effectStack.pop()
        }
    }
    return effect

}
// 保存依賴關系的數(shù)據(jù)結構 
const targetMap = new WeakMap()
// 弱引用 不去影響垃圾回收機制
// 2. 依賴收集:建立 target/key 和 fn 之間的映射關系
function track(target,key) {
    // 1. 獲取當前的副作用函數(shù)
   const effect = effectStack[effectStack.length - 1]
   if(effect){
    // 2. 取出 target/key 對應的map
    let depMap = targetMap.get(target)
    if(!depMap){
        depMap = new Map()
        targetMap.set(target,depMap)
    }
    // 3. 獲取key 對應的 set
    let deps = depMap.get(key)
    if(!deps){
        deps = new Set()
        depMap.set(key,deps)
    }
    // 4. 存入set
    deps.add(effect)
   }
}
// 3. 觸發(fā)更新函數(shù): 當某個響應數(shù)據(jù)發(fā)生變化,根據(jù) target key 獲取對應的 fn并執(zhí)行他們
function trigger(target,key) {
    // 1. 獲取 target/key 對應的set 并遍歷執(zhí)行他們
    const depMap = targetMap.get(target)
    if(depMap){
        const deps = depMap.get(key)
        if(deps){
            deps.forEach(dep =>dep());
        }
    }
}

const state = reactive({
    name:"yzs",
    children:{
        age:3
    }
})
// state.children.age
// state.children = {num:2}
effect(()=>{
    console.log("effect-1",state.name);
})
effect(()=>{
    console.log("effect-2",state.name,state.children.age);
})
state.name = "yzs001"
state.children.age = 30

參考資料

vue3


初心

我所有的文章都只是基于入門,初步的了解筹陵;是自己的知識體系梳理;
如果能幫助到有緣人,非常的榮幸,一切為了部落的崛起;
共勉
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末益老,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子瞻鹏,更是在濱河造成了極大的恐慌悲立,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件新博,死亡現(xiàn)場離奇詭異薪夕,居然都是意外死亡,警方通過查閱死者的電腦和手機赫悄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門原献,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馏慨,“玉大人,你說我怎么就攤上這事姑隅⌒戳ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵讲仰,是天一觀的道長慕趴。 經常有香客問我,道長鄙陡,這世上最難降的妖魔是什么冕房? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮趁矾,結果婚禮上耙册,老公的妹妹穿的比我還像新娘。我一直安慰自己愈魏,他們只是感情好觅玻,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著培漏,像睡著了一般溪厘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牌柄,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天畸悬,我揣著相機與錄音,去河邊找鬼珊佣。 笑死蹋宦,一個胖子當著我的面吹牛,可吹牛的內容都是我干的咒锻。 我是一名探鬼主播冷冗,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼惑艇!你這毒婦竟也來了蒿辙?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤滨巴,失蹤者是張志新(化名)和其女友劉穎思灌,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恭取,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡泰偿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜈垮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耗跛。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡裕照,死狀恐怖,靈堂內的尸體忽然破棺而出课兄,到底是詐尸還是另有隱情牍氛,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布烟阐,位于F島的核電站搬俊,受9級特大地震影響,放射性物質發(fā)生泄漏蜒茄。R本人自食惡果不足惜唉擂,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望檀葛。 院中可真熱鬧玩祟,春花似錦、人聲如沸屿聋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽润讥。三九已至转锈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間楚殿,已是汗流浹背撮慨。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脆粥,地道東北人砌溺。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像变隔,于是被迫代替她去往敵國和親规伐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容