《前端技術架構與工程》之性能筆記

《前端技術架構與工程》之性能

前言:

《前端技術架構與工程》這本書真的越看越有味。目前寫了部分這本書的筆記,共分爲三部分做筆記,已寫了兩篇如下。

《前端技術架構與工程》初次筆記

《前端技術架構與工程》之編程語言

今天準備寫技術架構部分(編程語言、技術規範、組件化、前後端分離、性能)中的性能部分。

初次筆記讓我從架構師的角度認識前端技術棧,編程語言筆記讓我對前端三大件有了新的理解。

雖然技術規範、組件化、前後端分離裏面的知識也重要,但是我這三部分都要了初步瞭解,勉強夠用。唯一性能這一塊沒有去深入瞭解,而性能這一塊又挺重要的。於是今天特意先做一下性能這一塊的筆記。結合《前端技術架構與工程》的第六章以及前端學習梳理 的性能優化部分進行展開。

我的筆記只是二手資料,詳情請自行找資源。

性能

性能是衡量軟件架構最基本也是最核心的直播之一。在前端領域,HTML5新增的web worker可實現多線程和並行計算以提高運算性能;CSS3的transform 3D藉助GPU加速提高動畫流暢度;Node.js得益於V8引擎優異的性能表現而普及。互聯網產品,尤其是TOC產品,性能是影響用戶體驗的核心因素之一。瞭解性能的優化是有必要的。

在以用戶爲中心的互聯網時代,優秀的用戶體驗的web應用搶佔市場的重要武器,而性能的決定用戶體驗的核心。加載速度快能夠給用戶良好的第一印象,流暢的交互是支持功能最具象的要素。

  • 在加載性能上,網絡架構層是優化宗旨是減少延遲以提高數據獲取的速度,異步script能夠減少JavaScript代碼對渲染的阻塞從而令HTML文檔儘快渲染;
  • 在應用執行期間,熟知瀏覽器GC策略有助於編寫對內存友好的代碼,可避免因內存泄漏導致的應用程序交互卡頓甚至死機的現象。

在《前端技術架構與工程》的性能部分主要從性能評估模型、從URL到圖形、內存管理、極限運算性能這四部分進行講述。

  • 在性能評估模型中:講性能指標;
  • 從URL到圖形:講如何在加載階段和可交互階段優化性能,方法是獲取數據和渲染HTML文檔;
  • 內存管理:講在瀏覽器有限的內存配額下如何優化代碼以防止內存泄漏;
  • 極限運算性能:將在大數據處理的項目如何發揮瀏覽器的極限運算性能;

性能評估模型

制定性能評估模板最基本的原則是:對客戶端場景參數(設備、瀏覽器、網絡)賦予固定的值,使得應用限定在一致的客戶端場景中,然後再進行對比。

web應用程序的生命週期分兩個階段:一是加載階段(從輸入URL到顯示網頁的階段),二是可交互階段。

性能評估(貫穿這本書的基本原則,技術服務於業務)分爲:加載性能、動態性能、業務性能;

加載階段

加載階段的性能被稱爲加載性能。優化加載性能可細分爲兩個方向:一是從視覺角度提高網站內容的渲染速度,對應白屏時間和首屏時間兩項指標;二是從交互角度縮短打開網站到可交互之間的時間間隔,對應可交互節點指標;在這本書第二章將預渲染的時候就有白屏的優化方案。

可交互階段

加載結束,網站進入可交互階段,由於可交互是動態的,故此階段的性能定義爲動態性能。優化動態性能也有兩個方向:一是反饋速度,如新加載內容的加載;二是動畫幀率,不過這個不做深入瞭解,目前佔個坑;

業務性能

業務性能單獨挑出來講,因爲技術服務於商業,商業的優先級遠高於技術。在加載階段,業務性能指標有兩個:首次有效繪製和廣告可視節點;在可交互階段,業務性能指標有關鍵路徑渲染。

從URL到圖形

談到網頁性能優化就不可避免需要了解從URL到頁面的具體過程。這個過程不僅和加載相關也和交互相關。學習前端不僅需要學習HTML、CSS、JavaScript,還需要對瀏覽器的實現過程熟悉,雖然它不能直接提高代碼的質量和開發的效率,但是能爲方案設計提高堅實的理論基礎。

瀏覽器的大致架構分爲三層:操作系統層、內核層、應用層;

  • 應用層:包含一些可視化的交互模塊,如書籤管理、窗口管理等;以及一些不可見的數據管理模塊,如歷史記錄等;
  • 操作系統層:提供瀏覽器所需的系統API,如多線程、文件I/O等;
  • 內核層:瀏覽器的核心,包括兩個部分,一是渲染引擎,包括HTML、CSS、SVG的解釋器和JavaScript引擎,以及佈局、繪製相關的模塊;二是相對底層的功能模塊集合,如網絡模塊、圖形庫、存儲、多媒體解碼器;

其中內核層是優化web應用性能的主要突破點,無論加載性能還是動態性能,其中的關鍵點就在於網絡方面、渲染方面、運算方面;

瀏覽器打開URL的完整流程依次是:當前文檔卸載、重定向處理、緩存判斷、DNS查詢、建立TCP連接、HTTP請求/響應處理、HTML文檔解析。在這過程中,截止至開始渲染前,瀏覽器的所有操作實質上就是嘗試獲取URL對應的信息,這一部分可以定義爲Fetch階段;接收到HTML文檔的HTTP響應後,瀏覽器開始解析和渲染工作,這一階段可以定義爲Render階段。在Fetch階段的時間消耗主要取決於網絡環境,不受前端代碼的影響;在Render階段的時間消耗受網絡環境和前端邏輯代碼的雙重影響。

網絡

Fetch階段。流程爲當前文檔卸載、重定向處理、緩存判斷、DNS查詢、建立TCP連接、HTTP請求/響應處理。

  • 當前文檔卸載:如果當前爲空白頁則無此操作;
  • 重定向處理:瀏覽器在處理重定向上的時間消耗非常大,現實中應當儘量避免。
  • 緩存判斷:fetch start。如果有緩存就直接返回緩存數據,沒有就繼續請求。
  • DNS:DNS server。絕大多數瀏覽器都有DNS緩存管理功能,可以節省一部分時間。
  • TCP、HTTP請求/響應:web server。獲得域名對應的IP後,瀏覽器便嘗試與Web服務器建立TCP連接,成功後隨即發生HTTP請求,收到響應數據後便進入Render階段。

在上述流程中不難看出,影響耗時的幾個重要因素。

  • 緩存,應用緩存和DNS緩存;
  • DNS查詢耗時。DNS查詢請求優先使用UDP協議,時間消耗非常小;
  • 建立TCP連接的三次握手和慢啓動好事。TCP慢啓動是一種爲了防止阻塞崩潰的安全機制,但是很耗時。
  • 瀏覽器發出HTTP請求和服務器處理響應數據的耗時。
  • 瀏覽器下載HTTP響應數據的耗時。這一項取決於網絡帶寬和URL對應資源的大小。

爲了優化這些耗時。有兩個思路。一個是減少RTT的總數量。一個是縮短RTT的時長。減少RTT的總數量的方法有持久連接、並行請求、HTTP combo;縮短RTT的時長的方法是CDN技術。

此外還有HTTP2.0,但是難以普及,一方面瀏覽器的兼容性不理想,另一方面是服務器遷移成本太高。所以針對網絡的優化策略仍然面向HTTP1.1。其優化策略是

  • 整體架構上:使用持久連接、使用CDN、控制域名數目、無法合併的小體積文件使用HTTP combo;
  • 前端上:壓縮文件體積、合併小體積文件(使用字體圖標)、合理使用緩存、按需加載、避免不必要的下載。

渲染

瀏覽器在渲染過程在有三種基礎數據,及定義網頁結構的HTML、描述視覺樣式的CSS和承擔交互行爲的JavaScript,每種數據類型均有對應的解釋模塊。

HTML解釋器將HTML文檔解析爲DOM樹。CSS解釋器將CSS解析爲CSSOM,渲染引擎按照CSS選擇器規則將DOM與CSSOM關聯之後對每個DOM應用樣式和佈局,最終繪製爲可視的UI。

瀏覽器在渲染HTML文檔期間,每逢遇到非異步的scrip標籤則暫停文檔後續內容的解析和渲染,待JavaScript文件加載和執行完後才恢復解析。之所以對scrip標籤應用阻塞式的解析策略,是英文JavaScript擁有改變HTML文檔結構的權限,它會改變DOM樹的具體形態,進而影響最終的視覺效果。

內存管理

JavaScript是一種擁有GC機制(全GC)的編程語言,GC機制能夠使開發者從繁瑣的內存管理工作中解脫出來,很大程度上提升開發效率和代碼的容錯性。但是由於GC屬於解釋層模塊,所以業務開發者幾乎沒有干預空間,一旦出現內存泄漏便只能靠解釋器的GC策略進行調整。

GC算法

JavaScript引擎最常見的兩種GC算法:標記清除算法、引用計數算法。

標記清除算法是目前應用較廣泛的GC算法之一,絕大多數JavaScript引擎的GC算法都是在標記清除算法基礎上的變中,比如V8的標記壓縮算法。標記清除算法分爲兩個階段:標記階段和清除階段。在標記階段以根節點爲起點,使用深度優先搜索算法向下遍歷所有對象,隨後清除階段把沒標記的對象刪除,並且把已標記的對象的標記信息也清除以便下次GC流程正常進行。(補充邏輯部分略)

引用計數算法是IE6和IE7引擎採用的GC算法,但是目前已經絕跡。雖然這個已經成爲了歷史產物,但作爲對比,有助於理解標記清除算法。略。

標記清除算法是目前實行JavaScriptGC策略的最佳選擇。

內存泄漏

在運行應用程序時,計算機管理內存的一般流程是 分配-使用-釋放,如此循環。

內存泄漏指的是一些分配出去的內存空間在使用完後沒有釋放。這些殘留的冗餘對象毫無用處卻佔據內存空間。大量的內存泄漏會造成因內存不足而導致應用程序崩潰甚至宕機。

造成JavaScript內存泄漏的根本原因是不合理的引用。由於JavaScript引擎的GC操作在語言層面是完全封閉的,開發者沒有任何干預的權限,只能通過編寫合理的代碼以避免發生內存泄漏。

內存泄漏的處理方法

避免全局變量。

在全局作用域內創建對象非常容易引發內存泄漏。並且還有命名衝突、破壞封裝性、存在安全隱患等弊端;

謹慎處理閉包。

閉包可以在函數內部引用外層作用域的變量,是JavaScript的核心特點之一,但是使用不當很容易造成內存泄漏。

使用編譯工具。

前兩種方法是盡力寫出好的代碼。第三種方法就是通過前端自動化工具幫助檢測,令code smell自動暴露出來。

極限運算性能

網絡體驗最差的地方就是:加載緩慢和操作卡頓。加載緩慢的情況仍然存在,操作卡頓的情況慢慢減少,出了代碼質量這種不可控的因素外,造成加載緩慢和操作卡頓的原因分別是網絡延遲和瀏覽器的運算能力。造成網絡延遲的因素是多方面的,需要從多方面同時切入優化。造成操作卡頓的原因非常單一,瀏覽器非常有限的運算能力是唯一的瓶頸。不過現代瀏覽器的運算能力越來越強了,vue等框架使得最消耗性能的DOM操作實現了輕量化和精細化。

不過開發者不能毫無顧忌,業務需求的增長速度遠超技術的發展,web應用的體量終有一天會增長至如今的幾十倍。並且目前複製圖形類web應用(如遊戲、VR等)已經非常接近瀏覽器運算能力的瓶頸。

web worker與並行計算

單線程的JavaScript無法實現並行計算,當瀏覽器處理計算量龐大的邏輯時會使用戶的任何操作均得不到反饋。web worker是HTML5規範的一部分,藉助它可以在瀏覽器後臺創建獨立的worker線程運行JavaScript代碼,實現多線程並行計算。

webAssembly

意思爲適合web的彙編語言,是運行與瀏覽器環境的二進制代碼。其定位是應對要求高性能的業務場景,如3D遊戲、webVR/AR、音視頻等。

WebGPU

對於核心聚焦在交互邏輯和UI的前端來說,設計高性能計算的項目計劃沒有純粹的數據計算,絕大多數是複雜的圖形類應用。基於此,便可以把圖形編程領域的諸多優化策略帶入前端領域。

最典型的就是將計算交付給比CPU性能更高的GPU來執行。隨着Flash的淘汰,WebGL基本通知複雜圖形類web應用的開放市場。webGL的着色器邏輯在GPU中執行,計算性能遠高於JavaScript。

題外話

《高性能網站建設指南》的借鑑

其中的14條規則挺有用的,可以借鑑。之後這本書的作者2010年還出版了《高性能網站建設進階指南》。

別人的筆記可以借鑑一下:《高性能網站建設指南》筆記

最好是看原書。

規則1:儘量減少HTTP請求

規則2:使用CDN

規則3:添加Expires頭

規則4:採用Gzip壓縮組件

規則5:將樣式表放在頂部(使用link標籤將樣式表放在文檔head中)

規則6:將腳本放在底部

規則7:避免CSS表達式

規則8:使用外部JavaScript和CSS

規則9:減少DNS查找

規則10:精簡JavaScript

規則11:避免重定向

規則12: 刪除重複腳本

規則13:配置ETag(配置或移除ETag)

規則14:使Ajax可緩存

有些內容我還看不太懂。不過其中有不少可以借鑑,如

  • 減少HTTP請求數量
  • 將CSS放到head中
  • 將外部腳本置底
  • 資源合併和壓縮
  • 避免重複的資源請求
  • 懶加載
  • 代碼優化。

把CSS放在頭部的原因是,在加載HTML生成DOM樹的時候,就可以同時對DOM樹進行渲染。這樣可以防止閃跳、白屏或者佈局混亂;

把JavaScript放在後面的原因是,JavaScript可能會改變DOM樹的結構,所以需要一個穩定的DOM樹。並且JavaScript加載後會立即執行,同時阻塞後面資源的加載。

最後,本來是想寫自己的理解,卻沒想到這裏許多內容都感覺有必要寫出來。大家如果感興趣的話,親自看書體驗更佳。

更新地址:GitHub

更多內容請關注:CSDNGitHub

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章