Proxy 的性能,可能比 DefineProperty 更差
老有人跑來跟我說 Proxy 和 defineProperty 相比,是性能的巨大提升。我一聽,這不對勁啊,跟我學的知識不太一樣,我明明記得Proxy 性能比 defineProperty 更差。
所以我就寫了幾個簡單的例子來驗證一下。
這個例子的邏輯非常簡單,我們在大數(shù)據(jù)量循環(huán)的過程中,分別用 Object.defineProperty 與 Proxy 劫持的數(shù)據(jù),執(zhí)行一次 getter 與 setter。然后利用 performance.now 記錄執(zhí)行時間。
先看 defineProperty 的案例。
首先定義一個簡單對象。
// 在循環(huán)中,我們會執(zhí)行計算操作
var target = {
total: 0
}
然后另外定義一個普通變量用于存儲劫持過程中訪問和設置的值。
然后用 Object.defineProperty 劫持 target。
Object.defineProperty(target, 'count', {
get: function () {
return b;
},
set: function (value) {
b = value;
},
});
然后循環(huán) 1000000 次,并打印執(zhí)行時間。
var total = 0;
var now = performance.now()
for (let index = 0; index < end; index++) {
total += target.count;
target.count = index;
}
console.log('defineProperty', performance.now() - now)
接下來看使用 Proxy 的案例。
也是首先定義一個普通對象。
var target = {
count: 0
}
然后使用 Proxy 代理。
let proxy = new Proxy(target, {
get: (target, prop, receiver) => {
return Reflect.get(target, prop, receiver)
},
set(target, prop, value) {
return Reflect.set(target, prop, value)
}
});
然后循環(huán)訪問 getter 和 setter。
var total = 0;
var now = performance.now()
for (let index = 0; index < end; index++) {
total += proxy.count;
proxy.count = index;
proxy.count
}
console.log('Proxy', performance.now() - now)
完整代碼如下:
<script>
var end = 1000000
var b = 0;
var target = {
count: 0
}
Object.defineProperty(target, 'count', {
get: function () {
return b;
},
set: function (value) {
b = value;
},
});
var total = 0;
var now = performance.now()
for (let index = 0; index < end; index++) {
total += target.count;
target.count = index;
}
console.log('defineProperty', performance.now() - now)
</script>
<script>
var end = 1000000
var target = {
count: 0
}
let proxy = new Proxy(target, {
get: (target, prop, receiver) => {
return Reflect.get(target, prop, receiver)
},
set(target, prop, value) {
return Reflect.set(target, prop, value)
}
});
var total = 0;
var now = performance.now()
for (let index = 0; index < end; index++) {
total += proxy.count;
proxy.count = index;
}
console.log('Proxy', performance.now() - now)
</script>
我的測試電腦如下,性能強悍,對應的瀏覽器都是最新版。因此這里我們都定義的是 1000000 萬次的執(zhí)行,以更加方便的放大差異。
理論上絕大多數(shù)客戶的電腦性能都很差,特別是許多面向 B 端的客戶,所以如果有條件的朋友可以用客戶的環(huán)境來做一下測試看看客戶電腦上的真實差異
在 chrome 中執(zhí)行結(jié)果為:
我連續(xù)執(zhí)行了 10 次,發(fā)現(xiàn)執(zhí)行結(jié)果都相差不大,執(zhí)行時間上,Proxy 用時更久。
然后我切換瀏覽器,在 safari 中執(zhí)行同樣的代碼,執(zhí)行結(jié)果如下:
結(jié)果沒想到,在 safari 瀏覽器中,Proxy 的性能嚴重低于 defineProperty。
然后我又把代碼發(fā)給群友,群友用 QQ 瀏覽器執(zhí)行了一下。
萬萬沒想到的是,firefox 的執(zhí)行結(jié)果差異最大。
然后我又嘗試讓 Proxy 代理的對象增加層級,然后進行 set 操作。
注意,這里只是簡單的增加對象復雜度,并不代表更深層級的屬性也能被代理。
var target = {
count: 0,
b: {
c: 0
}
}
for (let index = 0; index < end; index++) {
total += proxy.count;
proxy.count = index;
proxy.b.c = target.count
}
驗證結(jié)果發(fā)現(xiàn),當層級變深,執(zhí)行消耗的時間越長。下圖是 chrome 的執(zhí)行結(jié)果。
結(jié)論
在常用的幾種瀏覽器中,測試結(jié)果比較統(tǒng)一,Proxy 的性能都弱于 defineProperty,在 safari,firefox 中,defineProperty 的性能大幅度領先。
當 Proxy 的目標對象深層次 getter/setter 時,會增加更多的性能損耗。
針對 Proxy 的性能,chrome 優(yōu)化做得最好。但依然小幅度弱于 defineProperty。
針對于 defineProperty 的性能,firefox 和 safari 做得比較好,大幅度領先其他瀏覽器。