記一次比較Vue2和Vue3響應(yīng)式原理和性能差異

關(guān)注公眾號 前端人,回復(fù)“加群”
添加無廣告優(yōu)質(zhì)學(xué)習(xí)群
寫在前面
Vue響應(yīng)式原理是數(shù)據(jù)驅(qū)動視圖的核心,它能夠自動幫助開發(fā)者監(jiān)聽數(shù)據(jù)的變化,最終觸發(fā)視圖更新。它是Vue的渲染更新過程的核心。
那么了解這一部分的原理至關(guān)重要,這篇文章就結(jié)合vue2和vue3響應(yīng)式來做一個對比,既明白了響應(yīng)式原理的實現(xiàn),又對比了二者在性能上的差異~
需要了解的api
這篇文章不是零基礎(chǔ),需要對一些基礎(chǔ)api有一定的了解,那么這里給出這些api的官方文檔,供大家參考學(xué)習(xí):
vue2響應(yīng)式原理 Object.defineProperty vue3響應(yīng)式原理 Proxy Reflect
準(zhǔn)備一個原始對象數(shù)據(jù)
為了做這個實驗,我使用同一個數(shù)據(jù)對象來分別做vue2和vue3的示例:注意這個data數(shù)據(jù)從最外層花括弧到最里層總共8個層級,你可以數(shù)一下。
const data = {
username: 'tom',
profile: {
city: 'beijing',
a: {
b: 12,
c: {
d: 23
}
}
}
}
接下來我分別寫點代碼對這個數(shù)據(jù)做響應(yīng)式處理:
vue2
const data = {
username: "tom",
profile: {
city: "beijing",
a: {
b: 12,
c: {
d: 23,
},
},
},
};
function observe(data) {
console.log(1);
if (typeof data !== "object" || data == null) {
return data;
}
for (const key in data) {
defineReactive(data, key, data[key]);
}
}
function defineReactive(target, key, val) {
observe(val);
Object.defineProperty(target, key, {
get() {
console.log(`get ${key}`);
return val;
},
set(newValue) {
console.log(`set ${key}`);
if (newValue !== val) {
observe(newValue);
val = newValue;
}
},
});
}
observe(data);
console.log(data);
打印的結(jié)果如下:
從圖中可以清晰的看到總共打印了8次1,也就是說observe一共執(zhí)行了8次;由此可見vue2是一次遞歸到底的來實現(xiàn)響應(yīng)式的,好接下來看看vue3:
vue3
function observe(data) {
console.log(1);
if (typeof data !== "object" || data == null) {
return data;
}
const p = new Proxy(data, {
get(target, key, receiver) {
console.log(`get ${key}`);
const result = Reflect.get(data, key, receiver);
// 當(dāng)獲取值的是時候 再設(shè)置響應(yīng)式
return observe(result);
},
set(target, key, val, receiver) {
console.log(`set ${key}`);
const result = Reflect.set(target, key, val, receiver);
return result;
},
});
return p;
}
const data = {
username: "tom",
profile: {
city: "beijing",
a: {
b: 12,
c: {
d: 23,
},
},
},
};
const p1 = observe(data);
console.log(p1);
打印結(jié)果如圖:

只打印了一次1,也就是說observe只執(zhí)行了一次,從代碼可以看出,將來執(zhí)行g(shù)et的時候,observe又會再次執(zhí)行。什么意思呢?也就是說Vue3對于數(shù)據(jù)的深層監(jiān)聽只有當(dāng)獲取值的時候才會響應(yīng)式處理,這樣在性能上肯定會提升很多。爭議
讀到這里,拋開其他細(xì)節(jié)來講,可能你會來句臥槽,那Vue2也可以在get的時候observe啊,確實如此,但是想一下是不是會有點問題呢?問題就在于每次執(zhí)行g(shù)et的時候,不管是獲取哪個屬性,都需要執(zhí)行一下observe,并且它還是會向下遍歷,這樣增加了時間復(fù)雜度,可想而之,其性能是多么浪費的,還不如一次性深度監(jiān)聽到底呢?
而proxy則不一樣,它只會響應(yīng)式處理你get的那個層級,它不會深度遍歷,這樣解釋你明白了嗎?
總結(jié)
接下來總結(jié)一下二者響應(yīng)式的差異
Object.defineProperty
深度監(jiān)聽,性能問題 新增刪除屬性問題,這個可以參考我前面寫的一個文章總結(jié)一下Vue那些常用必會面試必考的API,這里說明了vue2為什么需要set&delete兩個api 數(shù)組問題,需要重寫數(shù)組原型的幾個方法
Proxy
性能提升了一大截 解決了vue2的那些問題 兼容性有待處理
當(dāng)然示例代碼都沒做優(yōu)化,實際上源碼肯定是對各種情況還做了處理,這里就不做介紹了,可以自己去看源碼哈~如果你對本文有什么看法或者覺得不對的地方,請在評論區(qū)賜教!共勉進(jìn)步~~
原文:juejin.cn/post/6933953813657157646
回復(fù) 資料包領(lǐng)取我整理的進(jìn)階資料包回復(fù) 加群,加入前端進(jìn)階群console.log("文章點贊===文章點在看===你我都快樂"Bug離我更遠(yuǎn)了,快樂離我更近了
