前端優化系列 - 初始化的性能影響分析

摘要:
前言 數據代表,即便在資源有緩存的狀況下,頁面首次訪問的耗時也是非首次訪問的兩倍。 爲何首次訪問這麼耗時呢,時間去哪裏了?本文詳細分析頁面首次訪問耗時的緣由。 常見的初始化 咱們先看看打開一個頁面,須要通過那些流程。

前言

數據代表,即便在資源有緩存的狀況下,頁面首次訪問的耗時也是非首次訪問的兩倍。前端

爲何首次訪問這麼耗時呢,時間去哪裏了?本文詳細分析頁面首次訪問耗時的緣由。數據庫

常見的初始化

咱們先看看打開一個頁面,須要通過那些流程。可能會包括,外殼初始化,內核初始化,建立WebView,建立Renderrer進程,初始化V8 JS引擎,初始化IPC,初始化CC,初始化網絡庫,初始化文件系統,初始化數據庫,啓動ServiceWorker線程,DNS解析,建立網絡鏈接,頁面服務器初始化,等等。這些流程前端通常是看不見的。小程序

在討論具體的耗時以前,咱們先約定,下文全部的數據都是基於Nexus 5手機。不一樣的手機的性能數據差別極大,一些高端手機(好比,iPhone X),性能多是中低端機的好幾倍。瀏覽器

外殼初始化

咱們先看看瀏覽器外殼的初始化,用戶點擊桌面圖標啓動瀏覽器,瀏覽器會進入一個狀態機,按步驟初始化各個模塊,不少模塊的初始化會涉及網絡,文件IO,JNI,等等操做,這些都會有必定的耗時。緩存

固然,全新安裝首次啓動,外殼初始化的過程當中,通常最耗時的是加載SO和JAR,其中使用DexClassLoader去加載JAR文件,在一些中低端機器,特別是Android 5.0之前的系統,耗時是以秒計算的,有些甚至能夠達到10秒。非全新安裝首次啓動,加載SO和JAR的耗時會大幅降低,大概在500ms。性能優化

咱們爲何須要關心瀏覽器啓動的耗時呢?一些場景下,用戶經過掃碼或者點擊桌面圖標去訪問頁面,這個過程就會包含瀏覽器的啓動流程,咱們有必要了解這其中發生了什麼。服務器

對於內置瀏覽器內核的App,好比,支付寶,手淘,狀況又是怎樣的呢?咱們這邊暫時沒有支付寶和手淘的啓動性能數據,但模塊初始化,加載SO和JAR,這些流程都會有,時間不會很小。微信

在外殼初始化耗時方面,有沒有一些比較好的解決辦法呢?網絡

最好的辦法就是進程保活,如今國內不少手機廠商都會給微信,支付寶,等超級App去進程保活,用戶在任務列表殺掉了應用,其實進程還在。ide

若是是多進程的狀況,能夠提早建立進程,好比,微信和支付寶的小程序,用戶訪問時能夠直接使用預建立的進程。

內核初始化

咱們再來看看內核的初始化,與外殼的初始化相似,內核的初始化也須要加載SO和JAR,建立WebView和初始化各個功能模塊。

在建立WebView方面,全新安裝首次建立約1秒,非全新安裝首次建立約300ms,第二次建立約15ms。

首次建立Renderrer進程,初始化IPC,初始化CC,這些耗時在百毫秒的級別;

V8 引擎相關的初始化耗時也在百毫秒的級別,其中首次NewContext要20ms。

總的來講,首次訪問加載SO和JAR通常須要500ms,建立WebView和走完內核流程通常須要消耗500ms,也就是說,提早初始化內核和預建立WebView加載一個URL,跑一趟內核流程,能夠帶來約1秒的收益。

業務初始化

在頁面加載的過程當中,內核會有不少回調通知外殼,這些回調的處理上是否可能存在性能問題呢?

咱們發現,在一些App上,一些接口極可能會出現性能問題,好比,onPageStarted,shouldOverrideUrlLoading,shouldInterceptRequest。

這些接口爲何會出現性能問題呢?通常不少應用會在首次onPageStarted回調時執行復雜的業務邏輯,好比,初始化一些統計模塊,進行JS注入,等等。須要說明的是,onPageStarted並非同步接口,爲何也會有影響呢?由於它是在UI線程執行的,長期佔用UI線程,會對內核有較大的影響,內核不少操做須要拋轉到UI線程去處理,好比,ServiceWorker線程啓動就有拋轉UI的過程,在UI執行完以前,它只能等待。

shouldOverrideUrlLoading 是客戶端攔截請求的關鍵接口,內核會同步等待,不少應用會有比較複雜的攔截規則。

shouldInterceptRequest 是客戶端離線包的關鍵接口,內核會同步等待,不少應用會在這個接口首次回調時去解壓離線包和初始化離線模塊。

在一些實際應用中,優化這些回調的處理,能夠給所有H5頁面帶來 10% 以上的性能提高。

ServiceWorker初始化

ServiceWorker是PWA的關鍵技術,它具備很是強大的能力,Fetch,Cache,Push和Add to home screen,能讓前端開發者很是靈活的操控頁面緩存。

同時,它也是有比較大的初始化成本的,好比,ServiceWorker線程啓動平均要200ms,而每次訪問頁面,通常ServiceWorker線程至少都須要啓動一次。固然,Chrome也在不斷優化這塊的耗時,最終預計能優化到100ms之內。

網絡初始化

在網絡初始化方面,通常內核網絡庫的初始化並不太耗時,耗時的是DNS和Connection。

用戶首次訪問,通常都須要去進行DNS解析和建立鏈接,而在後續訪問時,通常均可以用上緩存或者預鏈接。

DNS解析,通常耗時在200ms以上,建立HTTP鏈接,通常耗時也在200ms以上,而建立HTTPS鏈接則須要600ms以上。

也就是說,用戶首次訪問時,若是不能提早建立鏈接,從性能的角度來講,是很是危險的。

這個方面咱們的建議是,使用HTTPDNS提早解析和緩存DNS,提早建立鏈接(好比,用戶點擊時)。

瀏覽器也有這方面的優化,好比,在加載主文檔時,提早發起子資源的預鏈接,但在一些託管網絡庫的應用來講,這些策略可能不會生效。

服務器初始化

頁面服務器和資源服務器,是否也須要初始化呢?通常也是須要的,好比,頁面訪問過以後,頁面服務器也會有一些緩存,用戶再次訪問時能夠直接使用緩存而無需走完整的流程,但這些緩存應該是大部分用戶都能共享的,因此實際影響很差評估。資源服務器也同樣,好比,圖牀,不少是按用戶手機屏幕和網絡類型來返回不一樣圖片的,用戶訪問過就會放到CDN緩存中。

暫時未有數據代表服務器初始化對頁面總體性能產生明顯影響。但咱們有另一份數據,在一個業務中,預建立WebView提早加載一次模版頁面,能讓全網平均性能優化100ms。其中,模版頁是304的,裏面的資源都是可緩存的,也就是說,這100ms的收益並不來於緩存,而是來於某些模塊的初始化。

JS初始化

這裏提到的JS初始化,並非前面說的JS引擎相關的初始化。JS初始化是指JS文件緩存到httpcache和解析編譯生成V8 Cache文件。不少數據代表,JS解析編譯佔JS耗時的35%以上,一些有巨型JS的頁面甚至能夠達到80%。在U4 2.0中,通常JS執行一次以後,就能夠生成V8 Cache,雖然V8 Cache能夠重複使用,但也存在被自動清理的狀況,因此提早執行一次仍是有收益的。

一些業務中,提早執行一次JS,在用戶真實訪問時,耗時從500ms降到200ms。特別是在一些超級App中,基礎JS基本都同樣,提早執行一次可能會帶來很是明顯的收益。

結束語

上面介紹了一些常見的初始化對頁面性能的影響,但願你們能瞭解到一些隱藏的信息,能開闊Web優化的思路。固然,這些點不必定會存在很大的性能問題,好比,一些業務模塊處理的很是好的App,在業務初始化方面不必定會有性能問題,須要根據本身的實際場景,具體問題具體分析。

做者: 小扎zack

原文連接

相關文章
相關標籤/搜索