Categories
程式開發

百度小程序框架性能優化實踐


移動互聯網中 Native App(NA) 和 H5 一直處在博弈狀態,在性能體驗和靈活性上艱難尋找著平衡,單從技術上來說,小程序就是 NA 和 H5 的又一次碰撞。小程序的靈活性已被證實,在性能方面,百度智能小程序從框架啟動、小程序包下載、小程序包加載以及渲染等 4 個方面進行了啟動速度優化。

GMTC 全球大前端技術大會(深圳站)2019 上,百度技術經理付嘉興結合百度側和小程序開發者側闡釋了提升自身小程序性能可採用的手段,並介紹了作為宿主如何將小程序框架與自身技術整合。本文即根據付嘉興的演講整理而成。以下為正文:

今天給大家講的題目是《百度開源小程序框架架構演進和性能優化實踐》。本次分享包含兩部分,第一部分是百度智能小程序整體的框架及演進,主要講百度小程序開發全流程概況、百度智能小程序框架,以及百度小程序多宿主運行保障;第二部分是百度小程序框架的性能優化,主要講整個小程序的啟動過程,以及從開發者角度,有哪些重要的優化點。

百度智能小程序整體框架及演進

整個移動互聯網一直是在 NA 和 H5 之間尋找權衡,NA 的性能好、能力強;H5 靈活性更高。我認為渲染分為兩派,一派就是 NA 渲染派,一派叫做 H5 渲染派。

  • NA 渲染派,比較有代表性的如 RN、Flutter;
  • Web 渲染派,比如百度的輕應用,以及之後做的小程序。

1. 開發全流程概覽

百度小程序框架性能優化實踐 1

百度曾經做過的 Web 渲染派的三個代表產品,分別是輕應用、直達號和小程序。

  • 輕應用,是 H5 + 端能力。它是一個標準的 H5,增加了一些 NA 的 API,比如定位等。
  • 直達號,在技術層面跟輕應用是一樣的。
  • 小程序,本質上是一個受限的 H5 + 大量豐富的 API + UI 組件。現在我們給小程序提供的 API 有 300 多個,組件有 30 多個,組件是有界面的。比如,視頻、地圖 。

為什麼小程序要受限,主要有兩個原因:

  • 保持體驗的一致性。 H5 太過靈活,JS 隨時可以去改變界面。
  • 安全考慮。因為我們提供了大量 API 和組件,且這些都是很底層的一些能力,比如電話號碼、賬號,肯定不能輕易開放給大家。

怎麼受限,主要有兩點:

  • 編寫語言,不再是直接寫 HTML ,而是用自定義語言 swan 來編寫 。
  • runtime 層有兩個棧,一個是渲染棧,一個是 JS 執行棧,這兩個棧從物理上隔離,以保障安全性。

2. 智能小程序框架

(1)開發運行全流程

百度小程序框架性能優化實踐 2

先簡單介紹一下整個百度智能小程序的開發流程。

  • 首先開發者用 swan 寫佈局;
  • 接著通過開發者工具打包,上傳到我們的小程序 B 端服務器;
  • 然後是小程序的審核流程,有機審、人審;
  • 最後是用戶點擊小程序時,客戶端請求小程序 C 端服務器,C 端服務器再從 B 端服務器獲取小程序包。整個過程都是加密傳輸,可以保證代碼的安全。

(2)百度智能小程序框架 -SWAN

百度小程序框架性能優化實踐 3

上圖是一個百度智能小程序的框架,我們內部命名為 SWAN。

分層結構如下:

  • 最上層是開發者基礎庫,命名為 swan-js ,開發者直接和這層打交道。 swan-js 負責兩件事情:(1)swan 代碼轉為 HTML,變成 WebView 可運行程序;(2)客戶端端能力的封裝暴露。
  • 再下一層是 swan-native。這裡面最核心的是 API 和組件的 NA 實現。其中雙棧管理也在這一層,另外標紅的 Extension 用於開發者宿主自身能力擴展使用,比如,貼吧宿主期望增加個發帖能力,就可以通過此機制。
  • 再下面這層叫 Porting Layer。這層是百度小程序為了實現開源,增加的一層與宿主的接口層。
  • 最下面這一層是宿主基礎能力層。如果宿主沒有這些能力,可以參考百度開源的參考實現,可直接集成到宿主使用。

3. 核心結構

(1)前端角度

百度小程序框架性能優化實踐 4

我們從前端的視角來看看雙棧結構。一個宿主客戶端可以運行多個小程序,並且在一段時間內保持存活狀態,每個小程序都有一個master 執行框架JS 和小程序開發者的JS,一個master 對應多個slave(slave 代表一個用戶可見的界面)。

(2)客戶端角度

百度小程序框架性能優化實踐 5

從客戶端角度來看雙棧結構,如上圖所示,master 負責執行JS,可以有兩種實現方式,WebView 或JS 引擎(V8/jscore),JS 引擎的效率更高;slave 的展現有WebView,為了加快WebView 的創建速度,設置cache;master 和slave 的通信通過消息總線。

master 不支持 BOM、DOM 和 WEB-API,小程序只能調用對外開放的能力。

(3)小程序 NA 組件與界面關係

百度小程序框架性能優化實踐 6

從體驗上看,小程序的體驗要好於 H5,其中有一點就是小程序會把一些 NA 的能力和 UI 融合到小程序裡面去。小程序的主體渲染還是基於 H5 技術,接下來我們講一下 NA 元素如何融入 UI 界面。

NA 元素與 H5 的關係有兩種,貼片關係、同層關係。

貼片關係:NA 元素在 H5 不在同一層,NA 浮在 H5 之上,H5 所有元素都不可以放到 NA 元素之上。因為不在一層,就需要處理滾動聯動,當檢測到 WebView 滾動 n 個像素, NA 元素也需要滾動 n 個像素。

同層關係:NA 元素在 H5 這一層,H5 的原生可以壓在 NA 元素之上。

百度小程序框架性能優化實踐 7

貼片、同層的界面層級樹如上。

百度小程序框架性能優化實踐 8

我們舉一個視頻組件同層的例子。視頻組件比較複雜,有 4 層。第1 層是視頻層,即原始視頻的圖像,第2 層是彈幕層,第3 層是用於視頻控制的控件層(比如,開始、暫停按鍵),第4 層Slot 層,視頻上面漂的H5 元素將被放到這層。

同層處理機制,先在H5(開發者寫的swan 會被轉為H5) 上打一個特殊的標記先佔位,屬性inline;瀏覽內核把這個區域的surface 拿出來給到NA 層,然後,小程序框架會把這個區域surface 塞給播放器,讓播放器直接在surface 上面繪製,達到同層。上面的彈幕、控件、Slot,都是 swanjs 層 H5 實現 ,Slot 層可以認為是一個容器,例如寫一個 video,其所有的子元素都會放在 Slot。

NA 的組件同層的技術方案還不太一樣,安卓和 iOS 也是有些區別的。像在 iOS 上,如果有些組件設置 over-flow ,它會天然支持這一套東西,但是安卓就需要瀏覽器內核來支持。

4. 小程序多宿主運行保障

百度小程序框架性能優化實踐 9

百度智能小程序是開放系統,可以運行在多宿主之上,那如何在多宿主上保證小程序運行體驗的一致性呢?

各個宿主集成了我們的小程序框架後,首先要跑 CTS 測試,通過之後才可以拿到小程序列表進行分發。

對於可選能力部分,各個宿主不是所有的能力都需要實現。比如,一些 AI 能力、push 能力。

如果一個小程序用到了可選能力怎麼辦?

兩個辦法,一是小程序和宿主之間的雙向選擇機制,小程序可以選擇我要分發到哪些平台,宿主也有權利選擇要分發到哪些宿主。二是,小程序做兼容。

Estension 機制

百度小程序框架性能優化實踐 10

上圖所示,標紅的是 Extension 機制,當宿主有一些定制化的要求時,可以使用此機制。作為宿主,需要做兩件事情,一是在 JS 層需要寫一套接口。二是在 Porting Layer 接口實現層實現一套能力。如果宿主覺得這個能力是通用的,可以反饋提案,審核通過後,百度小程序團隊會將提案合併到開源框架裡。

5. 章節小結

百度小程序框架性能優化實踐 11

百度智能小程序框架性能優化實踐

首先從用戶視角看看一個小程序的加載過程。

1. 百度智能小程序加載分階段過程

百度小程序框架性能優化實踐 12

拿微博舉例,如上圖所示。

  • 首先小程序被啟動後,先是一個 Loading 的過程,上面的 title 和下面的 tab(框架 NA 實現)顯示出來。
  • 第二張圖片我們定義為 FP(First Paint )階段。
  • 第三張圖下面有搜索框了,這其實是小程序包裡面的內容。它是通過 initdate 接口初始化渲染出來的,此階段我們定義為 FCP( First Contentfull Paint )階段。
  • 第四張圖,是小程序從網上拉到了實時的內容,然後更新到界面,我們將其定義為 FMP(First Meaningful Paint) 階段。
  • 最後一張圖,所有的元素都已經拉下來並展示了,用戶可以操作任何一個位置,我們將其定義為 TTI (Time to Interative) 階段。

2. 百度智能小程序

(1)性能基線

百度小程序在 2019 年底建立了 FMP 指標,它在開發者平台展示的名字為“上屏時間”。

我們統計了線上的一個 80 分位點,耗時是 1.9s。 (什麼是 80 分位點?比如,有 100 個請求過來了,然後我們把請求的耗時排序,第 80 個請求的耗時,我們就認為是 80 分位點。)

(2)性能歷史曲線

百度小程序框架性能優化實踐 13

如上圖所示, 2019 年百度小程序性能優化的歷史曲線。

FP 框架層從接近 3s 一直優化了現在的 1.1s 左右。

百度小程序的目標是讓小程序無線接近 NA 體驗。

3. 啟動流程

百度小程序框架性能優化實踐 14

接下來,我們從開發者角度看,還能優化什麼?

我們先看一下啟動流程,所有的啟動邏輯簡單串行羅列(實際是有一些步奏是並行的)。

4. 性能優化

開發者能夠做的性能優化主要有兩部分。一是小程序包的體積,二是業務數據。

接下來,我用三點來說明開發者可以做什麼。

(1)包體積優化

百度小程序框架性能優化實踐 15

建議包體積保持在 1M 以內,為什麼呢?

因為我們統計了一下,如果打開當次需要下載包,則這次的啟動時長會占到我們整個時長的 60%。 1M 的包,80 分位速度需要 1s+ 才能下載完成。所以要控制自己的包的體積。而且我們現在還只是看 80 分位,當我們拉到 90 分位,99 分位,這個是一個非常陡的曲線,惡化很嚴重。

包體優化機制

有兩個技術:一是分包技術和獨立分包技術,二是資源壓縮。

  • 分包技術 & 獨立分包技術

  • 分包技術

百度小程序框架性能優化實踐 16

一個小程序有很多頁面,但不是所有的頁面都是高 PV 頁面。很多頁面是用戶很少點到的,可以把這些頁面放到我們的分包去,主包放我們高 PV 的頁面。

分包不能夠獨立運行,比如,從搜索 feed 分發過去,它運行時需要把我們主包下載下來,但是因為它的概率低,不會影響絕大多數情況。簡而言之,就是用分包技術把非關鍵的頁面剝離出去。

用分包技術把非關鍵的頁面剝離出去之後小程序包的體積還是大的話怎麼辦?

  • 獨立分包技術

所謂獨立,就是說下載完這個包之後就可以運行,無需下載主包。此時的主包和獨立分包的區別就是,小程序總要有一個入口,這個入口的獨立分包,我們就命名為主包。

通過這兩項技術來減小我們的包體大小,將其保持在在 1M 以內。

  • 資源壓縮

百度小程序框架性能優化實踐 17

我們分析過一些小程序,發現有的包體裡包含 PC 圖片,這無疑增加了包的體積。建議如下:

  • 把圖片放到服務器,不要放在包裡面。
  • 壓縮圖片體積,比如,把 png 改為 jpeg 格式這樣體積可以減少 90%(不考慮透明度情況)。
  • 剔除無用資源。

App-js 需要通過分包來解決,最終我們要達到什麼目標?

  • 單個包控制在 1M 以內。
  • 文件數控制在 200 個以內。

(2) 數據拉取

數據拉取的目的是快速讓界面有內容,減少用戶的白屏時間。即使用戶是斷網的,也給他離線緩存一些數據。

百度小程序框架性能優化實踐 18

如上圖所示,這裡面提到了業務骨架屏和框架骨架屏。現在很多小程序都會參考H5 的實現,把H5 的漸進式加載骨架屏用到我們的小程序裡面,用了這種技術之後,反而會讓真實的內容展示的速度變慢,我們統計大概有300ms延遲。

為了解決骨架屏導致的內容展示延遲,我們做了一套框架層的骨架屏機制。按照我們這個機制來實現骨架屏,對性能的影響就會大大減少。策略上就是在 master 做 appjs 執行時,就讓 slave 加載框架骨架屏,並行執行。

自己寫的業務骨架屏,它什麼時候才展示?如上圖所示,當你把 App 、page、waitNotify 通知到渲染線程,到了 Ready firstRender 的時候才會渲染自己做的業務骨架屏,這個過程當然很慢。雖然你用了骨架屏,但是骨架屏和用戶點擊的這段時間還有大量的白屏時間。用框架骨架屏,白屏時間問題就會解決。用框架骨架屏,或多或少都會耗一點時間,雖然是並行的,但是依然在搶占手機的資源。

所以整體來看,站在客戶端或者站在框架的角度,我們是不建議用,但是也不反對用。如果要用就用框架骨架屏,影響最小。

百度小程序框架性能優化實踐 19

request 的優化,我總結主要是兩點,第一要早,第二要少。

  • “早”又可以分兩部分來說,一是提早發,二是不阻塞。

第一是提早發,請求得太晚,展示當然比較慢了。建議把網絡請求放在 onlaunch 裡面,這是我們給小程序開放的第一個事件,很多小程序會放到 page unload 裡面,這個就比較慢了。這兩個時間在線上 80 分位,大概差 200ms~300ms。

第二個是不阻塞,經常看到一些小程序,一起來以後,它要等用戶的授權、定位。通常定位涉及 XY 坐標,但是定位一旦涉及高度,就需要打開 GPS,這樣性能又會慢 2s~3s。如果不需要高度就不要去設置,否則非常慢。還有的小程序在使用的時候會讓用戶授權,如果不授權下面什麼也不展示,阻塞了。如果可以的話,建議在需要授權的時候再提示用戶,這樣用戶也不反感,也能加快啟動的速度。

  • “少”,主要分為兩點,一是非關鍵請求延後,二是只拉取一屏數據。

一個小程序運行後,可能有幾十甚至上百個網絡請求,小程序除了自己的業務還要打點,這會很大程度上影響我們的網絡速度。因為一般的宿主在底層的網絡庫都會設置線程池,請求多了就要排隊。小程序框架根本不知道某個請求是核心請求還是非核心請求,只能排隊。要是一上來全是一些打點的,業務就阻塞了。總之,整個頁面需要顯示的數據先請求,非關鍵請求延後。

二是只拉一屏數據,分段加載。

(3)渲染

setData 操作是較為昂貴的,盡量減少數據量和次數。

百度小程序框架性能優化實踐 20

如上圖所示,setData 是一個非常核心的 API, 當網絡數據回來,只有經過 setData 驅動渲染,內容才能顯示到界面上。

上圖是一個優化前和優化後的對比。我們可以看到,即使是 1K 的數據,也需要 20ms 左右的時間。如果 js 是用 WebView 來執行,首先一個 JS string,到了瀏覽器有 Renderer 線程、Browser 線程,變為 C 層的 string,然後再到我們 NA ,通過 Java interface,變成一個 Java string。然後到了 slave 以後還要再反過來,所以快不了。雖然我們做了一些優化,通過內核讓它變成一個內存指針優化切換,但是還是很昂貴。

百度小程序框架性能優化實踐 21

發現有些小程序在使用的過程中, setData 使用有很多不當之處,以下是使用 setdata 要注意的幾點 。

  • 減少調用 setData 次數。 goodcase:將多次 setData 合併成一次 setData 調用。
  • 減少 setData 數據量。 badcase:新一頁數據添加上之前頁面數據後再調用 setData。
  • 變量變化只更新變量不更新對象。

5. 性能自查

百度小程序框架性能優化實踐 22

性能自查主要有三個階段,即開發階段、測試階段和上線後。

  • 在開發階段這部分,我們有三個手段去性能自查,分別是工具體驗評分、性能面板(在客戶端上性能面板可以提示整個性能啟動的耗時)以及打點系統。
  • 在測試階段我們有兩個手段,一是錄屏,二是高速攝像頭,這兩個手段可以真實地反應用戶的體驗。
  • 上線之後,有開發者平台。

如何獲取技術的官方支持途徑?建議去開發者文檔和社群去獲取技術支持。

百度小程序框架性能優化實踐 23

6. 章節小節

  • 開發者可從包體積、數據請求、渲染三方面去優化性能。
  • 包體:1M 內。分包技術、壓縮圖片、無用資源剔除。
  • 骨架屏:如果要使用,建議採用框架骨架屏。
  • setData:減少頻度、減少數據量。

整體回顧如下圖。

百度小程序框架性能優化實踐 24

作者介紹

付嘉興,百度技術經理,2010 年西安交通大學計算機碩士,畢業後加入百度,先後負責百度App、Feed、小程序方面的技術工作,現任百度智能小程序客戶端技術經理,核心工作主要集中在持續優化小程序體驗,無限接近Native app 體驗,以及繁榮百度小程序開源聯盟。

本文轉載自公眾號百度App技術。

原文鏈接

https://mp.weixin.qq.com/s?__biz=MzUxMzk2ODI1NQ==&mid=2247484039&idx=1&sn=a6211b3a0f43524e88898aab11296b71&chksm=f94c5397ce3bda815e77d9c428498af6266b7f41fa1bb63d2e3d95dc2a8e49fb1c8919c9b410&scene=27#wechat_redirect