天天看點

ES6 Proxy 性能之我見

本文翻譯自https://thecodebarbarian.com/thoughts-on-es6-proxies-performance

Proxy是ES6的一個強力功能,它通過為 <code>get/set</code>一個屬性 設定"陷阱"(函數處理器)讓我們可以攔截對于對象屬性的操作。比如:

Proxy被稱贊為現在已經被廢棄的<code>Object.observe()</code>屬性的取代者。

然而不幸的是,Proxy有一個緻命缺陷:性能。

更打擊人的是,<code>Object.observe()</code>就是因為性能被廢棄的,而以我(原作者)對V8的了解,對于JIT(Just in Time,準時制)來說,<code>Object.observe()</code>比Proxy容易優化多了。

我(原作者)在node v6.9.0中用benchmark簡單試了一下:

結果如下:

從這個簡單的benchmark中我們可以看到,Proxy的<code>set</code> 比直接指派和defineProperty慢非常多(譯者注:ops/sec,每秒進行的操作數,越大越快)。

為防大家好奇,我(原作者)又在node 4.2.1測試了一下<code>Object.observe()</code>:

有些文章可能讓你覺得隻要Proxy不用<code>get/set</code>而是隻設定<code>getOwnPropertyDescriptor()</code>的話,就比其他的快,于是我(原作者)又試了試:

不幸的是,反而更慢了:

用Proxy包裹一個函數并調用同樣比原生的包裹函數并調用慢非常多:

目前最有影響力的提升Proxy性能的方法是讓被修改的屬性的configurable設為false:

(譯者注:這段代碼有些問題,<code>enumerable</code>在<code>configurable</code>為false時是無效的)

要是這樣寫<code>set/get</code>,還不如直接用 <code>Object.defineProperty()</code>。

這樣寫的話,你就不得不設定每個你要在Proxy中用到的屬性不可配置(not configurable)。

不然的話,V8就會報錯:

Proxy比 <code>Object.defineProperty()</code>有不少優點:

Proxy 可以嵌套,而<code>Object.defineProperty()</code>的<code>getter/setter</code>就不能嵌套,這樣你就不需要知道提前知道你要攔截的所有屬性

可以攔截數組變化

但它性能太差了。

性能有多大影響呢?

以Promise和回調為例:

Promise也慢了非常多,

但是 bluebird聲稱為Promise提供"非常好的性能",測試一下:

雖然快了很多,但仍然比回調慢不少。

是以我們要是以放棄Promise麼?

并不是這樣的,很多公司仍然選擇了使用Promise。我(原作者)雖然不是很确定,但是Uber好像就在使用Promise。

Proxy很慢,但是在你因其性能而放棄它之前,記得同樣性能很差的Promise在最近幾年中被快速采用。

如果你想使用代理,很可能你不會感覺到性能的影響,除非你發現自己為了性能的原因改變了Promise庫(或者完全避開了它們)。

2019.01, 在node v11.3.0中: Promise已經變得足夠好, Proxy還是那樣