色婷婷777国产AMSR_日本人妻永久视频网站_欧美特黄A级高清内谢视频_oursHDTV无码_国产1卡2卡三卡4卡5卡乱码

您當(dāng)前的位置:首頁 >> 電影 >  >> 
H5開屏從龜速到閃電,企微是如何做到的
來源:      時間:2022-12-19 14:29:35


【資料圖】

導(dǎo)讀|H5開屏龜速常是令開發(fā)者頭疼的問題。騰訊企業(yè)微信團隊對該現(xiàn)象進行分析優(yōu)化,最終H5開屏耗時130ms,達到秒開效果!企微前端開發(fā)工程師陳智仁將分享可用可擴展的Hybird H5秒開方案。該團隊使用離線包解決了資源請求耗時的問題,在這個基礎(chǔ)上通過耗時分析找到瓶頸環(huán)節(jié),進一步采用“預(yù)熱”進行優(yōu)化提速以解決了WebView初始化、數(shù)據(jù)預(yù)拉取、js執(zhí)行(app初始化)耗時的問題。希望這些通用方法對你有幫助。

背景

服務(wù)端渲染(SSR)是Web主流的性能優(yōu)化手段。SSR直出相比傳統(tǒng)的SPA應(yīng)用加載渲染規(guī)避了首屏拉取數(shù)據(jù)和資源請求的網(wǎng)絡(luò)往返耗時。團隊針對Web開發(fā)也已經(jīng)支持了SSR能力。近期出于動態(tài)化運營的考慮,我們選擇了Web開發(fā),同時我們也接到了提升體驗的訴求。以企業(yè)微信要開發(fā)的頁面為例:采用SSR方案,從用戶點擊到首屏渲染的耗時均值約600ms,白屏?xí)r間的存在是可以感知到的。為了盡可能消除白屏達到秒開效果,我們嘗試做更多探索。方案思路1) 方案選型如何實現(xiàn)頁面秒開呢?從最直觀的渲染鏈路來入手分析。下圖列出了從用戶點擊到看到首屏渲染可交互,一個SPA應(yīng)用主要環(huán)節(jié)的加載流程。我們調(diào)研了業(yè)內(nèi)相關(guān)方案,從渲染鏈路的視角來看下常見方案的優(yōu)化思路。傳統(tǒng)離線包在加載渲染過程中,網(wǎng)絡(luò)IO是很明顯的一個耗時瓶頸。傳統(tǒng)的離線包方案思路很直接,如果網(wǎng)絡(luò)耗時那就將資源離線,很好地解決了資源請求的耗時。用Service Worker也能達到離線包的效果,同時也是Web標(biāo)準(zhǔn)。首次渲染優(yōu)化一般需要結(jié)合客戶端配置預(yù)啟動腳本來達到緩存資源的效果。SSRSSR則從另外的角度出發(fā),在請求頁面的時候就進行服務(wù)端數(shù)據(jù)拉取和頁面直出,首屏得以在一個網(wǎng)絡(luò)往返就可以展示,有效地規(guī)避了后續(xù)需要等待css/js資源加載、數(shù)據(jù)拉取的時間。性能體驗有比較大的提升,在BFF普及的情況下開發(fā)模式簡單,很受歡迎。公司內(nèi)相關(guān)工作考慮到WebView的初始化(冷啟動/ 二次啟動)、頁面網(wǎng)絡(luò)請求、首屏數(shù)據(jù)接口的耗時,白屏?xí)r間還是可感知地存在的。以我們要開發(fā)的頁面為例采用SSR首屏耗時均值~600ms,可交互時間均值~1100ms。如何進一步消除白屏?這里為各位介紹公司內(nèi)外針對h5首屏性能優(yōu)化的優(yōu)秀方案。手Q團隊的VasSonic是集大成者,主要思路是采用WebView和數(shù)據(jù)預(yù)拉取并行的方式。這套方案需要客戶端和服務(wù)端采用指定協(xié)議改造接入,開發(fā)時也有一定的改造工作。微信游戲團隊主要思路是利用jsCore做客戶端預(yù)渲染,用戶點擊后直接上屏。這個方法也達到了很好的效果,首屏FCP時間從1664ms降低到了411ms。我們做了一個簡要的方案對比,可以看到每個方案都針對渲染鏈路的某個或多個環(huán)節(jié)做了優(yōu)化,其中VasSonic的效果比較顯著。不過結(jié)合企業(yè)微信業(yè)務(wù)實際情況,我們列出了如下幾點考慮:首先,接入對客戶端和服務(wù)端有一定的改造成本,業(yè)務(wù)開發(fā)也有一定的改造工作。其次,我們已經(jīng)有一套的統(tǒng)一發(fā)布平臺,希望能復(fù)用這套發(fā)布能力。最后,性能上有沒有進一步優(yōu)化的空間呢?業(yè)務(wù)需求對體驗上的要求是希望達到更好的性能效果或者說盡可能完全地消除白屏?;谝陨峡紤],我們在上述方案的基礎(chǔ)上做了進一步的實踐探索,以期望達到更好的性能效果。
離線包SSRVasSonicCSR
資源加載
數(shù)據(jù)拉取
JS執(zhí)行
WebView啟動優(yōu)化
首屏FCP
可交互(取決于JS執(zhí)行)
2)方案架構(gòu)為了達到盡可能完全消除白屏,我們還是從初始問題出發(fā),結(jié)合渲染鏈路進行分析,思路上針對每個環(huán)節(jié)采取對應(yīng)的優(yōu)化方法。每個環(huán)節(jié)的優(yōu)化在具體落地時會存在著方案的利弊取舍。比如預(yù)拉取數(shù)據(jù)一般的思路是交給客戶端來做,但是存在著客戶端請求和h5請求兩套機制(鑒權(quán)、請求通道等方面)如何協(xié)調(diào)的問題。在渲染鏈路分析時,如果業(yè)務(wù)的js執(zhí)行也貢獻了不少耗時,有沒有可能從通用基礎(chǔ)方案的角度來解決這個問題,同時也能減少業(yè)務(wù)對性能優(yōu)化的關(guān)注?這是個值得各位思考探索的問題。具體的內(nèi)容會在后面展開來說。如圖展示了方案的優(yōu)化思路和主流程。方案使用離線包解決了資源請求耗時的問題,在這個基礎(chǔ)上通過耗時分析找到瓶頸環(huán)節(jié),進一步采用預(yù)熱的思路進行優(yōu)化提速,解決了WebView初始化、數(shù)據(jù)預(yù)拉取、js執(zhí)行(app初始化)耗時的問題,最終達到了理想的性能體驗。圖1 上屏流程圖2 方案架構(gòu)下面我們具體介紹下方案,包括:離線包技術(shù)、預(yù)熱提速和進一步的優(yōu)化工作。離線包加速為了規(guī)避資源請求耗時,我們使用了離線包技術(shù)。離線包技術(shù)是比較成熟的方案,相關(guān)打包、發(fā)布拉取的方案這里不多說了,主要說下方案中一些設(shè)計上的考量。1)加載流程我們通過offid作為離線包應(yīng)用的標(biāo)識,fallback機制保證離線資源不可達時用戶也可以正常訪問頁面,通過離線包預(yù)拉取和異步檢測更新機制提高了離線包命中率,盡可能消除了網(wǎng)絡(luò)資源加載的耗時。2)fallback機制因為用戶網(wǎng)絡(luò)狀況的不確定性,離線包加載可能存在失敗的情況。為了保證可用性,我們確定了離線包加載不阻塞渲染的思路。當(dāng)用戶點擊入口url,對應(yīng)offid離線包在本地不存在時,會fallback請求現(xiàn)網(wǎng)頁面,同時異步加載離線包。所以我們針對離線包的打包結(jié)構(gòu),按照現(xiàn)網(wǎng)URL path來組織資源路徑。這樣客戶端請求攔截處理也會比較方便,不需要理解映射規(guī)則。當(dāng)發(fā)現(xiàn)離線包不匹配資源時,放過請求透到現(xiàn)網(wǎng)即可。如圖展示了我們的離線包結(jié)構(gòu)示例。3. 離線包生命周期為了提高離線包命中率,我們會配置一些時機(e.g.入口曝光)來預(yù)拉取離線包。離線包的更新機制:客戶端加載時根據(jù)offid檢測到本地離線包的存在,則直接使用拉起,同時啟動異步版本檢測和更新。如果新包版本號大于本地版本號則更新緩存,同時發(fā)布平臺也支持區(qū)分測試環(huán)境、正式環(huán)境以及按條件灰度。上了離線包后,可以看到頁面的首屏耗時均值從基準(zhǔn)無優(yōu)化的1340ms降到了963ms,離線包的預(yù)拉取和更新策略則使離線包命中率達到了95%。首屏耗時得到了一定的降低,但也還有比較大的優(yōu)化空間,需要更一步的分析優(yōu)化。預(yù)熱提速通過離線包的加速,我們解決了資源請求耗時的問題,不過從整個渲染鏈路來看還有很大的優(yōu)化空間,我們做了具體的耗時分析,找出耗時瓶頸,針對耗時環(huán)節(jié)做了進一步的優(yōu)化提速。1)耗時分析離線包技術(shù)規(guī)避了資源請求耗時,但是從整個渲染鏈路來看還有很大的優(yōu)化空間,我們做了耗時分析如下。Hybird應(yīng)用中,WebView初始化是比較耗時的環(huán)節(jié),這里我們針對iOS WebView做了測試。
首次冷啟動/ms二次打開/ms
iOS(WKWebView)480ms90ms
數(shù)據(jù)拉取方面,不同入口頁面的耗時不一,某些入口頁面比較重的接口耗時超過了1s。此外,我們發(fā)現(xiàn)js執(zhí)行也貢獻了不少耗時。以某入口頁面為例,框架初始化時間~10ms,app初始化時間~440ms。2)渲染鏈路預(yù)熱提速預(yù)熱流程我們的目標(biāo)是消除白屏,這里理想的方案是找到一種和業(yè)務(wù)無關(guān)的通用解法。方案的主要思路是預(yù)熱,把能提前做的都做了。預(yù)熱是不是就是把WebView提前創(chuàng)建出來就好了呢?不是的,這里的預(yù)熱涉及到多個渲染環(huán)節(jié)的優(yōu)化組合。如圖展示了預(yù)熱的整體流程,下面一個個來解。2)WebView預(yù)創(chuàng)建為了消除WebView的耗時,我們采取了全局的預(yù)創(chuàng)建WebView,時機為配置入口曝光。不過全局復(fù)用預(yù)熱WebView不可避免地會引入可能的業(yè)務(wù)內(nèi)存泄露問題,下文會介紹對應(yīng)的規(guī)避方案。數(shù)據(jù)預(yù)拉取數(shù)據(jù)拉取是頁面渲染的一個耗時環(huán)節(jié)。為了消除數(shù)據(jù)預(yù)拉取耗時,在預(yù)創(chuàng)建WebView階段我們同時進行了數(shù)據(jù)預(yù)拉取。數(shù)據(jù)預(yù)拉取常見的思路是交給客戶端來做,但是存在著客戶端請求和h5請求兩套機制如何協(xié)調(diào)的問題,以請求鑒權(quán)為例,存在以下的問題:第一,Web團隊自身有一層node BFF,實現(xiàn)了相應(yīng)的數(shù)據(jù)拉取業(yè)務(wù)邏輯,而客戶端則走的私有協(xié)議通道請求C++后臺,二者是不同的鑒權(quán)機制。第二,如果交給客戶端來做,可以接入HTTP請求這套機制,改造成本比較大,如果復(fù)用原有通道,則一份數(shù)據(jù)業(yè)務(wù)邏輯需要兩套實現(xiàn)。如何設(shè)計一套通用可擴展的方案?我們希望做到客戶端只關(guān)注容器的能力(預(yù)熱、資源攔截等),屏蔽掉更深入的對Web的感知,這樣的解耦可以有效控制方案的復(fù)雜度。因此,這里我們針對離線包配置項增加了preUrl字段,使客戶端維護更通用的能力,數(shù)據(jù)預(yù)拉取交給業(yè)務(wù)團隊來做,具體如下:第一,客戶端:拉取某個離線包配置項時會讀取該字段,同時針對當(dāng)前曝光的入口url可能存在多個有著不同的數(shù)據(jù)需求,這里會進行收集,將曝光url中的業(yè)務(wù)key參數(shù)拼接到preUrl來初始化WebView,這些作為通用能力。第二,業(yè)務(wù):preUrl頁面在加載時會拉取相應(yīng)的業(yè)務(wù)數(shù)據(jù)存到localStorage,實際的數(shù)據(jù)預(yù)拉取請求放到業(yè)務(wù)方發(fā)起,也可以很好地兼容已有的技術(shù)棧。JS預(yù)執(zhí)行很接近目標(biāo)了,最后js執(zhí)行的耗時能不能消除呢?首先來看下440ms的耗時具體在哪里,通過分析看到,框架初始化僅需要不到10ms的時間,而真正的大頭在業(yè)務(wù)代碼的執(zhí)行,其中代碼編譯耗時~80ms,其余的都是業(yè)務(wù)app初始化執(zhí)行時間,這個是業(yè)務(wù)本身復(fù)雜度造成的。我們首先考慮了創(chuàng)建兩個WebView的方案,一個負(fù)責(zé)加載preUrl預(yù)拉取數(shù)據(jù),另一個負(fù)責(zé)loadUrl上屏,這樣設(shè)計上比較簡潔健壯,不過實踐下來發(fā)現(xiàn)效果不理想,如圖展示了該方案的效果,渲染不穩(wěn)定可以感知到白屏的存在。在已經(jīng)有了預(yù)拉取數(shù)據(jù)和離線資源的情況下,理論上用戶點擊后需要等待的就只有渲染這塊的耗時,實際我們發(fā)現(xiàn)在復(fù)雜應(yīng)用初始化時存在js執(zhí)行耗時較大的問題。最終我們做了一個預(yù)執(zhí)行的解法。結(jié)合SPA的特點,將preUrl作為SPA的一個子頁面,不需要UI展示,只負(fù)責(zé)預(yù)拉取數(shù)據(jù),這樣子頁面加載完成的同時也完成了app提前初始化。而相應(yīng)的不同入口切換頁面時,不同于復(fù)用預(yù)熱WebView重新reload頁面,為了保留app初始化的效果,我們采取了一套Native通知Web SDK,頁面切換交給WebView控制的方案。其中,Native通知則以調(diào)用SDK全局方法的方式。通過這種方式,入口頁面間切換其實只是hashchange觸發(fā)的子頁面渲染,達到了不錯的效果。流程圖即預(yù)熱方案的上屏部分。該方案執(zhí)行后我們達到了預(yù)期目標(biāo)效果,最大限度地消除了白屏接近Native體驗。需求上線后通過監(jiān)控數(shù)據(jù)可以看到在命中預(yù)熱和離線包邏輯的情況下,從用戶點擊到頁面上屏可交互耗時均值約130ms。進一步優(yōu)化1)離線包安全在離線包安全方面,為了防止包篡改,每我們次打包發(fā)布時都會生成包簽名和文件md5。客戶端在使用解析離線包時會校驗完整性,在返回離線資源時會校驗文件完整性。2)穩(wěn)定性整體方案在性能上已經(jīng)達到目標(biāo)了,保證穩(wěn)定性對產(chǎn)品體驗也很重要。我們?yōu)榱讼齤s執(zhí)行的耗時,采取了Native通知Web SDK控制頁面切換的方式。雖然比較靈活但是也帶來了穩(wěn)定性的問題。具體來說,如果SDK在做頁面切換時異常,之后用戶打開每個入口url都會看到相同的頁面。入口頁面的業(yè)務(wù)在用戶使用過程中如果跳轉(zhuǎn)了非SPA的鏈接同時沒有注入SDK,之后的頁面切換也會失效。如何保證預(yù)熱容器的可用性呢?我們設(shè)計了一套通知機制確??蛻舳烁兄筋A(yù)熱容器的可用狀態(tài),并在不可用時得以恢復(fù),如圖。預(yù)熱容器會維護isInit和isInvokedSuc兩個狀態(tài)。只有當(dāng)preUrl成功加載和SDK執(zhí)行成功上屏?xí)r,兩個狀態(tài)才會置true,此時的預(yù)熱WebView才是可用的,否則會回退到普通容器模式進行l(wèi)oad url來加載頁面。此外,在每次入口url曝光時,已有的預(yù)熱容器也會銷毀重建,也有效保證了容器的穩(wěn)定性。3)內(nèi)存泄露使用全局的預(yù)創(chuàng)建WebView,不可避免的會引入可能的業(yè)務(wù)內(nèi)存泄露問題。在測試過程中,我們也發(fā)現(xiàn)了這種例子??梢钥吹疆?dāng)點開使用了預(yù)熱容器的頁面后放置一段時間,整個內(nèi)存在不斷上漲,最終會導(dǎo)致PC端頁面的白屏或者移動端的Crash,這個狀況最終歸因是業(yè)務(wù)邏輯的實現(xiàn)存在缺陷。不過在基礎(chǔ)技術(shù)的角度而言,開發(fā)者也需要采取措施來盡可能規(guī)避內(nèi)存泄露的情況。主要思路是減少同一個預(yù)熱容器的常駐,也就是對存活的容器設(shè)置有效期,在適當(dāng)?shù)臅r機檢查并清理過期容器,我們選擇的時機是App前后臺切換時。4)解決副作用出于性能考慮,我們選擇了通過Web SDK控制頁面的方案,同時使用了全局的預(yù)創(chuàng)建WebView。這帶來了副作用——當(dāng)頁面對容器做了全局的設(shè)置,可能會影響到下一個頁面的表現(xiàn)。比如:設(shè)置document.title、通過私有JSAPI設(shè)置了WebView導(dǎo)航欄的表......當(dāng)執(zhí)行這些操作時,在下一個頁面也復(fù)用預(yù)熱容器的情況下,全局設(shè)置沒有得到清理重置或者覆蓋,用戶會看到上個頁面的表現(xiàn)。為了解決上述問題,業(yè)務(wù)可以在每個頁面主動聲明需要的表現(xiàn)來覆蓋上個頁面的設(shè)置,理想的方法還是基礎(chǔ)技術(shù)來規(guī)避這個問題來保證業(yè)務(wù)開發(fā)的一致性。我們在SDK控制切換頁面時,進行了一系列的重置操作。此外,在Windows和Mac端,我們也設(shè)計了雙預(yù)熱WebView的方案來完全解決這個問題。每次使用時同時創(chuàng)建新容器,得以保證每次打開入口頁面都是使用新創(chuàng)建的容器。當(dāng)然,方案的另一面則是會帶來App內(nèi)存的上漲??偨Y(jié)我們從渲染鏈路入手,針對每個環(huán)節(jié)進行分析優(yōu)化,最終沉淀了一套可用可擴展的Hybird H5秒開方案。從渲染鏈路的角度來看,方案通過離線包和預(yù)熱一系列優(yōu)化,將用戶從點擊到可交互的時間縮短到了一個SPA路由切換上屏步驟的耗時。上線后我們監(jiān)控發(fā)現(xiàn),命中了預(yù)熱離線邏輯的頁面首屏耗時~130ms,相比于離線包、SSR都有優(yōu)勢,同時預(yù)熱離線容器命中率也達到了97%,達到了理想的體驗效果。希望本篇對你有幫助。??

騰訊工程師技術(shù)干貨直達:

1、算法工程師深度解構(gòu)ChatGPT技術(shù)

2、10分鐘!從架構(gòu)視角讀懂K8s

3、探秘微信業(yè)務(wù)優(yōu)化:DDD從入門到實踐

4、耗時減半?騰訊云OCR只做了3件事

標(biāo)簽:

X 關(guān)閉

X 關(guān)閉