若是我告訴你,你知道的一切都是假的,若是你學的一些近幾年發佈的深受喜好的 ECMAScript 的主要特性,是很容易致使性能問題的,會發生什麼。javascript
故事發生在幾年前,讓咱們回到 ES5 的天真時代...前端
我深深地記得 ES5 發佈的那天,咱們喜好的 Javascript 引入了一些優秀的數組方法,它們是 forEach, reduce, map, filter——這些方法讓咱們感覺到語言不斷髮展,功能愈來愈強大,寫代碼變得更有趣和流暢,代碼變得更通俗易懂。java
幾乎同時,誕生了 Node.js ,它使得咱們能平穩地從前端過渡到後端,同時真正從新定義了全棧開發。數據庫
如今,Node.js ,在 V8 引擎上使用最新的 ECMAScript ,爭取被認爲是主流的服務端開發語言之一。所以,它須要證實在性能方面是高效的。固然,有不少性能參數須要考慮,沒有某種語言的性能能夠全部參數都優於其餘語言。可是,用開箱即用的方法如上面提到的函數寫 javascript 對你的應用性能的影響究竟是有利仍是有害呢?後端
此外 ,javascript不只僅是爲了展現視圖而被認爲是客戶端開發的合理方案,由於用戶的電腦性能會變得更好,網絡會更快,可是當咱們須要一個超高性能的應用或者很是複雜的應用時,咱們能依賴用戶的電腦嗎?數組
爲了測試這些問題,我嘗試比較幾個場景並深刻理解個人實驗結果,我在 Node.js v10.11.0、Chrome瀏覽器、macOS上作的測試。瀏覽器
1.遍歷數組服務器
我作的第一個場景是對一個 10萬條數據的數組求和。這是現實中一個有效的方法,我從數據庫中獲取了一個列表並求和,沒有額外的 DB 操做。網絡
我用 for , for-of, while, forEach, reduce 比較了在隨機的 10萬條數據中求和,結果以下:函數
For Loop, average loop time: ~10 microseconds
For-Of, average loop time: ~110 microseconds
ForEach, average loop time: ~77 microseconds
While, average loop time: ~11 microseconds
Reduce, average loop time: ~113 microseconds
複製代碼
從 google 上查如何作數組求和時,reduce 是推薦的最好的實現方式,可是倒是性能最差的。個人必用方法 forEach 性能也不是很好。即便是最新的 ES6 方法 for-of ,只是提供了最差的性能方法。它比舊的 for 循環方法(也是性能最好的方法)差了 10 倍。
最新的和最推薦的方法怎麼可使得 Javascript 變得如此慢,形成這個的緣由主要有 2 個。reduce 和 forEach 須要一個執行一個回調函數,這個函數被遞歸調用並使堆棧"膨脹",以及對執行代碼進行附加操做和驗證。
2.複製數組
複製數組看起來不是一個有趣的場景,但這是不可變函數的基石,它在生成輸出時不會修改輸入。
性能測試一樣出現了有意思的結果——當複製 10 萬條隨機數據時,用老方法仍是比新方法快。用 ES6 的擴展運算操做 [...arr] 和 Array.from, 加上 ES5 的 map 方法,arr.map(x=>x) 性能都不如老方法 arr.slice() 和 鏈接方法 [].concat(arr)
Duplicate using Slice, average: ~367 microseconds
Duplicate using Map, average: ~469 microseconds
Duplicate using Spread, average: ~512 microseconds
Duplicate using Conct, average: ~366 microseconds
Duplicate using Array From, average: ~1,436 microseconds
Duplicate manually, average: ~412 microseconds
複製代碼
3.對象迭代
另外一個常常遇到的場景就是對象迭代,一般就是咱們不能根據特定的 key取值,而必須遍歷 JSON 結構 或者 Object。咱們有老方法 for-in (for(let key in obj)),也有新方法 Object.keys(obj) 和 Object.entries(obj)。
咱們用上述方法,對 10 萬個對象,每一個對象都包含 1000 個隨機的 keys 和 values 進行性能分析。結果以下:
Object iterate For-In, average: ~240 microseconds
Object iterate Keys For Each, average: ~294 microseconds
Object iterate Entries For-Of, average: ~535 microseconds
複製代碼
出現這樣結果的緣由是,後兩種方案建立了可枚舉的數值組,而不是在沒有 keys 的狀況下直接遍歷數組。可是最終的結果仍然值得關注。
結論
個人結論顯而易見——若是性能對你的應用很關鍵,或者你的服務須要處理一些過載,那麼使用酷的,可讀性更高的,更簡潔的方法會對你的應用產生重大的性能影響——可能會慢 10 倍!
以後,在盲目跟隨新趨勢以前,先確保這些新方法是否知足需求,對於小應用,快速迭代和用高可讀性對代碼是完美的,可是對於壓力大的服務器和龐大的客戶端應用,可能不是最佳實踐。