我認為效能最佳化對許多開發人員感興趣,因為他們了解了完成任務的不同方法。一些內心的聲音問道:「哪種方式最好?」雖然「最佳」指標有很多變化,例如Douglas Crockford 的2008 年JavaScript:The Good Parts,但性能是容易所得的,因為我們可以自己測試它。
然而,測試和證明性能並不總是那麼容易做到。
到 2000 年代初期,Internet Explorer 贏得了第一次瀏覽器戰爭。 IE 甚至一度成為 Mac 上的預設瀏覽器。曾經佔據主導地位的網景公司被出售給美國在線並最終關閉。他們的衍生產品 Mozilla 對其新的獨立瀏覽器 Phoenix Firebird Firefox 進行了長達數年的測試。
2003 年,Opera 7 推出了 Presto,一種新的、更快的渲染引擎。 Apple 也發布了 Safari,這是一款基於鮮為人知的 Konqueror KHTML 引擎構建的 Mac 效能瀏覽器。 Firefox於2004年正式推出。微軟於2006年發布了IE 7,Opera 9發布了更快的JavaScript引擎。 2007 年,Safari 出現在 Windows 和新 iPhone 上。 2008 年出現了 Google Chrome 和 Android 瀏覽器。
隨著更多的瀏覽器和更多的平台,效能成為這段時期的關鍵部分。新的瀏覽器版本定期宣布它們是新的最快的瀏覽器。 Apple 的 SunSpider 和 Mozilla 的 Kraken 等基準測試經常在版本中被引用,而 Google 則維護自己的 Octane 測試套件。 2010年Chrome團隊甚至做了一系列「速度測試」實驗來展示瀏覽器的效能。
微效能測試在 2010 年代受到了廣泛關注。 Web 正在從有限的頁面互動性轉向完整的客戶端單頁應用程式。 Nicholas Zakas 的 2010 年高效能 JavaScript 等書籍展示了看似微小的設計選擇和編碼實踐如何能夠產生有意義的效能影響。
不久前,JavaScript 引擎競賽就致力於解決高效能 JavaScript 中的一些關鍵效能問題,引擎的快速變化使得很難知道什麼是最好的現在。隨著新的瀏覽器版本和行動裝置的出現,微效能測試成為一個熱門話題。到 2015 年,現已關閉的效能測試網站 jsperf.com 非常受歡迎,它開始因垃圾郵件而出現效能問題。
隨著 JavaScript 引擎的發展,編寫測試很容易,但很難確保你的測試公平甚至有效。如果您的測試消耗了大量內存,則後續測試可能會看到垃圾收集造成的延遲。設定時間是否已計入或排除在所有測試之外?測試是否產生相同的輸出?測試的背景重要嗎?如果我們測試 !~arr.indexOf(val) 與 arr.indexOf(val) === -1 ,如果我們只是運行表達式或在 if 條件下使用它,會有什麼不同嗎?
隨著腳本解釋器被各種編譯器取代,我們開始看到編譯程式碼的一些好處和副作用:最佳化。例如,在沒有副作用的循環中運行的程式碼可能會被完全優化。
// Testing the speed of different comparison operators for (let i = 0; i < 10000; i += 1) { a === 10; }
因為這是執行 10000 次操作而沒有輸出或副作用,所以最佳化可能會完全丟棄它。但這並不能保證。
此外,微優化在不同版本之間可能會發生顯著變化。 jsperf.com 的不幸關閉意味著不同瀏覽器版本的數百萬歷史測試比較丟失,但這仍然是我們今天可以看到的。
重要的是要記住,微優化效能測試有很多注意事項。
隨著效能改善開始趨於平穩,我們看到測試結果出現反彈。其中一部分是引擎的改進,但我們也看到引擎針對常見模式最佳化程式碼。即使有更好的編碼解決方案,優化通用程式碼模式對使用者來說也有真正的好處,而不是期望每個網站都進行更改。
比不斷變化的瀏覽器效能更糟糕的是,2018 年計時器的準確性和精度發生了變化,以減輕 Spectre 和 Meltdown 等推測執行攻擊。如果您有興趣的話,我寫了一篇關於這些時間問題的單獨文章。
讓事情變得複雜的是,您是否針對最新的瀏覽器或專案支援的最低瀏覽器進行測試和最佳化?同樣,隨著智慧型手機的普及,處理能力明顯較低的手持裝置成為重要的考量。知道在哪裡分配時間以獲得最佳結果 - 或最有影響力結果 - 變得更加困難。
過早的最佳化是萬惡之源。
——唐納德·高德納
這句話常被引用。人們用它來暗示,每當我們考慮優化時,我們可能會為了虛幻的或微不足道的收益而浪費時間並使程式碼變得更糟。在很多情況下這可能是正確的。但這句話還有更多內容:
我們應該忘記小效率,大約 97% 的情況下:過早的最佳化是萬惡之源。但我們不應該放棄這關鍵的 3% 的機會。
更完整的引用添加了關鍵上下文。如果我們允許自己這樣做,我們可以在小效率上花費大量時間。這通常會花費時間來實現專案目標,但無法提供太多價值。
我個人在這些優化上花了很多時間,目前看來並不算浪費。但回想起來,並不清楚這些工作有多少是值得的。我確信我當時寫的一些程式碼將執行時間縮短了幾毫秒,但我真的不能說節省的時間是否重要。
Google 甚至談到了 2017 年 Octane 測試套件退役的收益遞減。我強烈建議您閱讀這篇文章,深入了解致力於這項工作的團隊在效能優化方面遇到的限制和問題。
那我們要如何聚焦那「關鍵的3%」呢?
了解程式碼的使用方式和時間有助於我們更好地決定關注點。
不久之後,新瀏覽器的效能提升和變化就開始將我們從這些類型的微觀測試推向更廣泛的工具,例如火焰圖。
如果您有 30 分鐘的時間,我推薦這個關於 V8 引擎的 2015 Chrome DevSummit 演示。它討論的正是這些問題......瀏覽器不斷變化,跟上這些細節可能很困難。
對正在運行的應用程式進行效能監控和分析可以幫助您快速識別程式碼的哪些部分運行緩慢或運行頻繁。這使您能夠處於有利的位置來考慮優化。
使用效能監控工具和函式庫可以讓您了解程式碼如何運作以及哪些部分需要運作。它們還讓我們有機會了解不同的領域是否需要在不同的平台或瀏覽器上工作。也許 localStorage 在記憶體和 eMMC 儲存有限的 Chromebook 上要慢得多。也許您需要緩存更多資訊來應對緩慢或不穩定的蜂窩服務。我們可以猜測哪裡出了問題,但測量是更好的解決方案。
如果您的客戶群夠大,您可能會發現真實使用者監控 (RUM) 工具的好處,它可以讓您了解實際的客戶體驗。這些超出了本文的範圍,但我已經在幾家公司使用它們來了解客戶體驗的範圍,並將重點放在實際效能和錯誤處理上。
深入思考「我如何改進這件事」很容易,但這並不總是最好的答案。您可以退後一步並詢問“這是解決此問題的正確解決方案嗎?”來節省大量時間
在 DOM 上載入非常大的元素清單時出現問題?也許僅在頁面上載入可見元素的虛擬化清單可以解決效能問題。
在客戶端執行許多複雜的操作?在伺服器上計算部分或全部這些會更快嗎?部分工作可以快取嗎?
退一步:這是執行此任務的正確使用者介面嗎?如果您設計的下拉清單預計有 20 個條目,而現在有 3000 個條目,那麼您可能需要不同的元件或體驗來進行選擇。
對於任何表演作品,都存在一個次要問題:「什麼才夠」?有一個來自 Stand-up Maths 的 Matt Parker 的精彩視頻,講述了他編寫的一些代碼以及他的社區如何將其從運行時間週改進到毫秒。雖然令人難以置信的是,這樣的最佳化是可能的,但幾乎所有專案都有一個達到「足夠好」的點。
對於只運行一次的程序,幾周可能是可以接受的,幾個小時會更好,但你快速花費多少時間就成為一個重要的考慮因素。
您可能會認為它就像工程中的公差。我們有一個目標,我們有一個接受範圍。我們可以追求完美,同時明白成功和完美並不相同。
目標是最佳化的關鍵部分。如果你只知道當前狀態不好,「讓它變得更好」就是一個開放式目標。如果沒有優化之旅的目標,當您可以處理更重要的事情時,您可能會浪費時間嘗試尋找更高的效能或更多的最佳化。
我對此沒有一個好的衡量標準,因為性能優化可能會有很大差異,但盡量不要迷失在雜草中。這實際上與專案管理和規劃有關,而不僅僅是編碼解決方案,但在定義最佳化目標時,開發人員的輸入非常重要。正如“替代方案”部分中所建議的,解決方案可能不是“使其更快”。
就馬特·帕克的情況而言,他最終需要答案,並且不需要將該設備用於其他任何用途。在我們的世界中,我們經常衡量訪客表現及其可能的財務影響與開發人員/團隊時間以及您的機會成本,所以措施沒那麼簡單。
假設我們知道將添加到購物車的時間減少 50% 將使我們的收入增加 10%,但完成這項工作需要兩個月的時間。有什麼比兩個月的最佳化工作產生更大的財務影響嗎?你能在更短的時間內實現一些效益嗎?再說一次,這是關於專案管理而不是程式碼。
當您確實發現自己需要最佳化程式碼時,也是看看是否可以將程式碼與專案的其他部分分開的好時機。如果您知道必須編寫複雜的最佳化,這將使程式碼難以理解,那麼將其提取到實用程式或程式庫可以使其更容易重複使用,並允許您在需要隨時間變化時在一個地方更新該最佳化。
表演是一個複雜的話題,有很多曲折。如果你不小心的話,你可能會投入大量的精力卻收效甚微。好奇心可以是一位好老師,但它並不總是能取得成果。玩弄程式碼效能是有好處的,但也有時間分析專案中緩慢的實際來源並使用可用的工具來幫助解決它們。
以上是JavaScript 微觀效能測試、歷史與局限性的詳細內容。更多資訊請關注PHP中文網其他相關文章!