效能和體驗在 iOS / Android 雙端場景下已經是一個較為成熟的話題,但隨著鴻蒙 OS 的發展,端側開發者需要更多的關注多端場景的差異性。在 InfoQ 舉辦的 QCon 全球軟體開發大會(上海站)上小紅書鴻蒙工程師王勁鵬為我們帶來了精彩專題演講“小紅書鴻蒙 OS 下的效能最佳化探索與實踐”,分享議題將以獨特於雙端的視角,分享小紅書在鴻蒙 OS 上的效能創新實踐。
內容亮點:
-
詳細瞭解小紅書在鴻蒙 OS 上的效能最佳化實踐案例;
-
對比 Android/iOS 端的類同效能最佳化場景,以前端視角展示鴻蒙 OS 上特有的能力上有何不同。
以下是演講實錄(經 InfoQ 進行不改變原意的編輯整理)。
我分享的主題是小紅書在鴻蒙平臺上的工程實踐,主要聚焦於效能最佳化和探索。首先,我先介紹一下自己的背景。我之前一直從事大前端領域的工作,主要專注於跨端和容器化方案。我也曾手寫過一個跨端框架,名為 Doric,它可以對標 React Native、Vue Native 和 Flutter 等。Doric 框架在落地時表現良好,還支援了一些自研的 3D 引擎方案。除此之外,我還有播放器核心研發經驗,以及大前端常規體系建設和 CI/CD 流水線的工程經驗。未來,我將持續關注大前端的演進,尤其是鴻蒙這樣的多端和跨端平臺。
從 2023 年開始,鴻蒙的優勢愈發明顯,已經成為可與 iOS、安卓媲美的第三大移動作業系統。從一些抖音影片中也可以看出,鴻蒙在流暢性方面甚至在某些層面上超過了 iOS。
今天的演講內容分為四個部分。第一部分是介紹整個歷程和背景;第二部分是介紹鴻蒙 OS 的相關能力和小紅書在該平臺上的最佳化實踐;第三部分是透過鴻蒙 OS 提供的效能驗證工具,展示小紅書在鴻蒙平臺上的效能最佳化驗證方法、最佳化後的效能提升以及具體的收益和結果;最後一部分是總結和展望。
從 2023 年年中開始,鴻蒙的“千帆計劃”正式啟動,並很快升級為“鴻飛計劃”。小紅書作為 7 家頭部合作商之一,率先支援了鴻蒙,並於 2023 年 11 月中旬上線了一個基礎版的 beta 版本 APP。這個版本主要包含筆記瀏覽和影片筆記瀏覽兩大功能,以及一些簡單的個人設定。當時,小紅書的動作非常迅速,可以說是頭部應用廠商中對華為支援最為積極的品牌之一。
在整個鴻飛計劃中,我們規劃了三個核心里程碑:除了 2023 年 11 月的 beta 版本外,還包括 2024 年 6 月的 HDC 版本和 2024 年 9 月的商用版本。HDC 版本主要是針對華為正式宣發鴻蒙 3(HarmonyOS Next)開發者測試的情況。在 HDC 版本中,我們上線了許多小紅書特有的存量功能,包括影片拍攝、圖文拍攝以及多裝置協同等創新特性。而到了 2024 年 9 月的商用版本交付時,小紅書的核心功能已經基本與主端對齊。考慮到鴻蒙的開發週期僅有一年,小紅書的鴻蒙 APP 在這一年中要對齊開發了十年甚至十幾年的安卓和 iOS 版本,難度和壓力都非常巨大。
到 2024 年 9 月,除了對齊雙端的所有功能外,我們還開發了許多其他功能,包括華為支援的創新特性,例如智慧拖拽——使用者可以將圖片拖拽到中轉站或小藝等場景。此外,商用版本還支援了使用者呼聲較高的 HDR 或 Moonlight Photo 拍攝能力。
我從幾個維度來對比一下純血鴻蒙和安卓 OS 的主要區別。
-
核心架構純血鴻蒙的本質是微核心,而安卓是基於 Linux 宏核心。微核心只提供基礎的記憶體和檔案管理能力,驅動和其他系統能力都在 OS 之外。這樣做的好處是系統穩定性極高,即使應用崩潰,也不會導致整個系統崩潰(system crash)。而在 Linux 宏核心中,應用的不當行為可能會直接導致系統崩潰。
-
多裝置適配鴻蒙目前支援多種裝置型別,包括 Mate 60 Pro 這樣的直板手機、Mate X5 或非凡大師 XT 這樣的雙摺疊和三摺疊手機、平板電腦、車機,甚至華為正在研發的鴻蒙 PC。鴻蒙真正實現了類似 iOS 的多端整合能力,透過一套程式碼實現多端部署。其工程體系和架構支援單 HAP(Harmony Ability Package)多 HSP(Harmony Service Package)模組,指令集適配了 ARM64 等多種架構,開發者只需根據裝置尺寸適配 UI 展示即可。例如,在 2024 年 9 月 的華為全場景裝置釋出會上,餘承東展示了小紅書在從直板機到雙摺疊、三摺疊裝置上的適配能力,完全實現了響應式程式設計,不同裝置形態下有不同的瀏覽體驗。
-
開發工具和程式設計模型鴻蒙的開發工具和程式設計模型與安卓差異較大。鴻蒙更類似於 Flutter 的巢狀型容器佈局,而不是安卓那種面向物件的開發方式。在語言層面,鴻蒙完全封裝了底層邏輯,採用類似前端 Flux 單向資料流模式,透過資料變更驅動 UI 重新整理。這種模式類似於前端 Redux 或 MobX 框架中的 state 管理 。
從 2024 年 10 月 8 日公測開始,鴻蒙的應用生態正在逐漸繁榮。不過,目前像微信這樣的應用還處於搶先體驗階段。相比之下,安卓的生態已經相對成熟。鴻蒙的最終目標是打造全場景智慧裝置生態,涵蓋所有終端裝置,以及基於 OpenHarmony 核心開發的物聯網終端。它還支援多種晶片體系,例如瑞芯微 RK3568 等。
小紅書經過一年的迭代,其整體應用架構已經基本成熟。目前,整體程式碼量接近 200 萬行,達到了一個較高的複雜度。在一般成熟的 APP 架構中,通常會包含一些基礎底層能力,例如網路、磁碟儲存、埋點體系、APM(應用效能管理)系統,以及一些通用元件和能力。對於鴻蒙平臺,小紅書還具備一些特殊的公共通用能力。
我們開發了一個“一多框架”,這是一個支援一套程式碼多端部署的具體框架體系。透過這個框架,我們實現了多裝置的斷點控制功能。使用者可以根據裝置的尺寸和型別進行適配,因為華為裝置支援多端投屏。例如,使用者可以在手機上瀏覽小紅書,然後將內容投屏到車機上。比如使用者購買了一輛問界汽車,可以在車內透過車機繼續瀏覽手機上的小紅書內容,這種場景在駕駛時尤其有用。
除了底層框架,對於上層業務,小紅書還有一套自研的元件庫方案,這套元件庫承載了上層業務的多種功能,包括圖文筆記、影片筆記瀏覽,以及一些 Hybrid 容器能力。小紅書本質上在跨端開發中仍然使用了 React Native(RN)和類 Web 技術。RN 引擎由華為內部合作提供,採用了自研的 ohos 方案,用於解決 React Native 的 bundle 和 JS 載入以及渲染問題。此外,還包括產品定製層,這裡涵蓋了所有相關的裝置適配內容。

目前,安卓和 iOS 在效能最佳化方面已經相當成熟,包括如何分析效能熱點問題、有哪些工具以及最佳實踐等。然而,對於鴻蒙來說,它是一個全新的系統。直到 2024 年年中,鴻蒙的穩定性和流暢性都還存在一些問題。這裡重點講述小紅書在 2024 年與華為一起進行了哪些實踐,以提升應用的效能和使用者體驗。
我們定義了一個性能指標場景。這個指標體系是小紅書與華為共同探討的結果,因為華為有一個性能工廠,它對每個應用的評級都有一個 S 標標準。小紅書與華為一起確定了針對小紅書場景需要觀測的具體指標。效能最佳化的核心是慢函式指標,它主要包含兩部分:過程時長和應用體驗的流暢性。
過程時長主要包含以下三點:
-
冷啟動時長:這是使用者最關心的指標之一,即從點選應用圖示到應用完成動畫並展示第一幀的時間。對於多數應用,首頁通常有快取機制。例如,小紅書會快取使用者上次重新整理的筆記,淘寶會快取使用者上次瀏覽的商品內容。
-
場景完成時長:指完成某個特定場景所需的時間。
-
應用響應時長:指使用者操作介面後,介面真正發生變化的時間,即響應時延。
流暢性方面,最基礎的觀測指標是平均 FPS(幀率),包括丟幀數、最大連續丟幀數、丟幀卡頓次數以及卡頓率。卡頓率可以透過量化計算得出:當一個場景中出現丟幀時,丟幀的時長與場景總時長的比值即為卡頓率,它是一個小於 1 的百分比數值。
首先,針對 IO 場景,我們進行了相應的最佳化。鴻蒙 OS 的系統能力主要分為以下三個方面:
-
並行化能力鴻蒙 OS 提供了兩種並行化能力:Worker 和 TaskPool。Worker 類似於傳統的執行緒模型,每個 Worker 都有自己的記憶體空間和執行單元,支援透過訊息(message)進行通訊。TaskPool 則類似於協程或執行緒池,能夠動態管理執行緒數量,支援標記為 @concurrent 的函式直接在任務池中排程和執行。這兩種機制都支援執行緒間隔離,記憶體不共享。
-
多執行緒通訊和資料傳輸在多執行緒通訊方面,鴻蒙 OS 支援序列化資料傳輸和基於訊息(message)的通訊機制。此外,還引入了事件發射器(Emitter)用於系統事件的釋出和訂閱。這種機制允許執行緒間透過訊息傳遞來實現複雜的互動邏輯。
-
同步轉非同步機制鴻蒙 OS 支援基於 Promise 的非同步程式設計模型,包括 async 和 await 語法,以及 then 和 catch 方法。這種機制能夠有效提升應用的響應性和使用者體驗。
在並行化能力方面,鴻蒙 OS 提供了兩套基礎實現方式。開發者可以透過 RTS(執行時系統)實現並行化,也可以透過底層庫(如 C++ 標準庫中的)實現。不過,如果完全依賴底層庫,可能會導致開發效率下降。為了滿足業務需求,鴻蒙 OS 在年初引入了 Worker 和 TaskPool 能力。Worker 類似於傳統的執行緒模型,每個 Worker 都有獨立的記憶體空間和執行單元,支援透過訊息進行通訊。訊息可以包含可序列化的資料,也可以透過指標直接遷移資料。TaskPool 則類似於執行緒池,能夠動態管理執行緒數量,支援標記為 @concurrent 的函式直接在任務池中排程和執行。與安卓平臺的執行緒池不同,鴻蒙 OS 的 TaskPool 會根據硬體條件和任務負載動態調整執行緒數量。這種機制避免了安卓平臺中因執行緒池數量過多而導致的系統資源消耗問題。
接下來我們對比鴻蒙 OS 的 Worker 並行化能力和安卓端的相關特性。從多個維度來看,Worker 本質上不推薦手動建立,而是透過系統配置 build-provider.json 繫結 ETS 檔案來實現建立。這一點與安卓端並無明顯差異,安卓端可以透過 THREAD 等方式啟動執行緒。
在鴻蒙 OS 5.0 以下版本(如 4.2 版本)中,主要執行的仍然是安卓系統。這種情況下,安卓執行緒數量存在上限,這對應用開發者來說是一個挑戰。如果 SDK 整合過多,執行緒數可能超標,進而導致應用被系統強制終止,或出現業務場景異常崩潰等穩定性問題。
資料傳輸方面,鴻蒙 OS 為了最佳化 Worker 的效能和負載,對 Worker 的數量和單個 Worker 的傳輸上限進行了限制。鴻蒙 Worker 的單個傳輸上限類似於安卓中的 Binder 機制,也存在類似的傳輸限制。不過,安卓執行緒通常沒有嚴格限制,因為執行緒本質上是一個記憶體複製過程,除非開發者透過指標等方式自定義執行緒間資料傳輸。
在傳輸格式上,鴻蒙 OS 支援透過 Sendable 介面進行資料傳輸。Sendable 是一種註解方式定義的資料結構,具有傳染性,即如果一個類被標記為 Sendable,其關聯屬性也必須是 Sendable 型別。鴻蒙 OS 支援基礎資料型別(如 number、string)和集合型別作為 Sendable 傳輸的內容。對於跨模組呼叫,鴻蒙 OS 不允許 Worker 跨 HAP 或跨 HSP 呼叫。相比之下,安卓應用通常執行在一個或多個 Dex 檔案中,允許跨 Dex 或跨模組的執行緒間呼叫。
TaskPool 類似於雙端的協程概念,是一種輕量級執行緒,僅儲存函式。不過,TaskPool 與協程有所不同,它獨立於任務維度,且任務執行時長有限制(超過 3 分鐘會被系統自動回收)。安卓平臺可以透過 ASM 插樁技術對執行緒的建立和執行進行監控和最佳化,但輕量級執行緒或協程的實現通常依賴於執行緒池或協程機制。
TaskPool 中的任務預設支援資料轉移(transfer),不支援複製。此外,TaskGroup 不支援 SDK 初始化包的載入。某些同學習慣在非同步執行緒中觸發 SDK 的行為,在鴻蒙 OS 上可能會因 TaskPool 生命週期結束而導致變數被釋放。
關於並行化資料傳輸的 Sendable 概念,Sendable 透過系統提供的 SharedHeap(共享堆)實現傳輸。共享堆與本地堆(local Heap)的區別在於,共享堆支援 Sendable 化資料的傳輸,而本地堆則需要序列化。共享堆的管理和控制耗費了華為專家大量時間和精力,其中還涉及複雜的非同步鎖(async lock)機制。在 RTS 併發例項期間(包括 Worker、TaskPool 等),資料可以透過 Sendable 傳遞,但 Worker 需要使用單獨的 API。TaskPool 則完全支援 Sendable 的直接傳輸。這種非同步鎖機制允許在 TaskPool 或 Worker 中鎖定其他任務中的某些函式,實現執行緒間的同步,類似於安卓中的 synchronized 或其他鎖機制。

小紅書在一些典型化場景中已經實現了並行化處理。例如,網路請求是一個典型的耗時操作,因為請求過程中涉及驗籤和安全能力的處理,這些操作如果在主執行緒中同步完成,可能會導致應用掉幀。當用戶滑動時,掉幀現象會非常明顯,這通常是由於大量計算引起的。為了解決這一問題,我們採用了 Worker 化的方式,將這些操作移到 Worker 執行緒中,從而避免主執行緒的卡頓。
在進行埋點時,可能會涉及資料庫的 IO 操作,這些操作也不建議在主執行緒中執行。透過將這些操作放到 Worker 執行緒中,可以有效避免對主執行緒的影響。
針對雙列布局中的圖片和資源預載入,我們採用華為自研的 RCP 網路解決方案(類似於 HTTP),透過 Worker 執行緒在遠端進行下載,並在完成後將結果返回到主執行緒。此外,TaskPool 的應用場景也非常廣泛,例如檔案上傳、多媒體操作以及啟動任務的編排等。TaskPool 的優勢在於輕量化,避免了執行緒上下文切換帶來的不必要耗時。
關於冷啟動和首刷場景的最佳化。這部分主要包括兩個方面:模組的懶載入和動態元件的複用池。懶載入是應用開發中常見的最佳化手段,類似於安卓端的 class order 機制。當應用不需要某個類時,可以延遲載入該類,直到真正需要使用時才載入。這種方式可以顯著提高冷啟動階段的程式碼載入效率,從而大幅降低冷啟動時長。
動態元件和元件複用池則是為了解決 UI 元件重複建立的問題。在應用中,可能會有多種相同型別的 UI 元件(例如小紅書中的筆記元件)。為了避免重複建立帶來的開銷,我們希望在執行時儘量複用已有的元件,而不是頻繁地建立和銷燬。
我們透過特定的分析工具對懶載入進行了深入分析。如圖所示,我們能夠識別出啟動過程中載入的各種模組,包括 RNOH(React Native on Harmony)、Web engine(網頁引擎)、Red Player(播放器)等元件。這些模組的載入過程涉及到多個.so 檔案,即共享物件檔案。

透過自上而下的分析方法,我們可以清晰地看到每個模組載入的具體耗時。進一步分析這些.so 檔案與 RTS(執行時系統)的關聯,以及它們所引入的 Napi 的 TS 檔案。我們進行了懶載入潛在物件的分析,發現許多 RTS 實際上並不需要的類檔案已經被載入。這是因為開發者在編寫程式碼時,可能並未充分考慮到匯入一個類或方法對應用啟動延遲的影響。
為了最佳化這一過程,我們的目標是減少位元組碼中需要載入的類檔案數量,從而加快應用的冷啟動速度。華為提供的編譯器能夠將 RTS 編譯成 Ark bytecode(方舟位元組碼),這是一種高效的位元組碼格式。透過減少需要載入的類檔案數量,我們可以顯著提高應用的啟動速度。
華為還提供了一種懶載入的匯入方式,只有在真正需要使用某個類時,它才會被載入。這種懶載入機制有助於減少應用啟動時的資源消耗。這引發了一個問題:為什麼華為不預設採用全懶載入方式,即只有在使用時才載入類檔案呢?我已經將這個問題反饋給華為,並且系統側可能會考慮在未來的版本中預設採用懶載入方式,同時仍然允許使用者手動選擇非懶載入的方式進行類檔案的載入。

在小紅書的首頁場景中,筆記卡元件在多個場景中被複用。為了避免重複建立 UI 導致的效能消耗,我們採用了動態元件的概念。動態元件的核心原理是利用佔位符來延遲元件的建立,這與 Android 開發中使用 Stub 模式的概念相似。在這種模式下,可以使用一個代理物件(stub)來代表尚未初始化的元件,從而延遲元件的建立過程。當真正需要渲染元件時,再將渲染內容填充進去,從而避免每次呼叫構建函式(如 build)時的耗時。
佔位邏輯透過系統的 API 實現,涉及到 NodeContainer 和 NodeController 的繫結關係。Container 和 Controller 一一對映,由 NodeCore 進行管理。Container 僅管理當前展現的記憶體部分,使用完畢後需要將其放回池中進行回收和再利用。以冷啟動首刷為例,在啟動階段可以先獲取磁碟上的筆記內容,然後在 BuilderNode 中預先建立多個 Image 元件。這樣,在等待網路或推薦介面響應時,Image 元件已經建立完畢,從而在首頁重新整理時可以立即使用這些元件,這對於提高首刷非常有益。

對於元件複用池,當動態元件不再使用時,需要將其返回到元件池中。對於自定義元件,透過 NoteContainer 佔位方式,由 NodeController 進行管理。在需要建立子元件時,先在 NodePool 中查詢,如果找不到,則建立新元件;如果找到,則嘗試複用。流程圖展示了從 Container 裝載 NodeItem 開始,透過 NodePool 查詢,如果找到則進行條件判斷和複用。
元件的新建和複用過程中,如果找到對應的 NodeItem,則呼叫 build 方法並更新自定義元件的狀態,完成複用。如果有對應的 NodeItem,可以直接透過 update 函式更新內部狀態並重新整理 UI。但要注意,update 方法可能會因狀態變數過於複雜而導致更新延遲,出現影像殘影。因此,需要拆分 state,使其足夠小,以確保狀態變更到通知 UI 的時間縮短,消除殘影。
我們的策略是優先在 NodePool(節點池)中查詢可用的 NodeItem(節點項)。如果 NodePool 中存在可用的 NodeItem,我們就直接使用它,並透過 getNode 方法進行 item 繫結,隨後更新其狀態以實現複用。如果 NodePool 中沒有找到對應的 NodeItem,那麼我們將透過 makeNode 方法呼叫 build 函式來建立新的節點項。
完成元件的複用後,我們需要將這些元件返回到快取池中,以便在未來可以再次使用。這個過程涉及到 NodeContainer(節點容器)和 NodeController(節點控制器)的銷燬,並將 NodeItem 重新放回 NodePool 中。為了更有效地管理快取,業務層可以利用 LRU(最近最少使用)演算法,或者鴻蒙系統提供的 LRUCache 和 LiUHashMap 等資料結構,來自定義快取的大小,從而最佳化元件的複用和快取策略。
在小紅書應用中,滑動類場景非常普遍,包括推薦頁的子頻道、個人頁中的收藏點贊以及使用者自己釋出的筆記,還有搜尋結果頁中的搜尋結果和使用者商品等,這些都是雙列滑動場景。這些雙列滑動場景佔據了小紅書使用者體驗的 90% 到 95%,因此,滑動體驗的流暢性對於使用者的整體體驗至關重要。
為了提升滑動場景的流暢性,小紅書採用了 RCP 框架來最佳化網路資源的獲取。RCP 是華為提供的一個系統元件能力,主要解決網路資源獲取效率問題。透過 RCP,開發者可以在需要時發起網路請求,並自定義資源的寫入地址,如檔案或 ArrayBuffer。RCP 負責高效地將資源寫入指定位置,而在不需要時,可以取消 RCP 請求,從而最佳化資源管理。

RCP 的核心能力在於能夠取消請求,並對弱網場景進行了最佳化,其建聯過程優於 HTTP 1.1 或 2.0。基於 RCP,小紅書還應用了華為俄研所提供的 Prefetch 方案。Prefetch 方案在瀑布流元件的可見區變更時,透過 worker 執行緒(如 prefetched worker)啟動資源獲取,當不可見時關閉,從而最佳化快速滑動場景,減少不必要的頻寬消耗。
在快速滑動過程中,有些 item 可能短暫消失,對於雙端場景,網路請求可能已經發出且在途,無法取消,導致頻寬浪費。Prefetch 和 RCP 結合的方式可以最佳化這種快滑場景,防止真正想要看的內容出現白塊。Prefetched worker 執行緒管理多個 RCP 請求,每個請求都有完整的生命週期。當透過 RCP 請求獲取到所需資源時,會通知主執行緒,主執行緒根據地址載入資源到 Image 元件或佔位符 RQI 元件中。
在小紅書的開發過程中,我們遇到了一些效能熱點問題,這些問題大多是透過 Code Linter(程式碼檢查工具)檢測出來的。由於開發節奏快,開發者在編寫程式碼時可能難以關注到效能問題,因此需要 CI(持續整合)檢查工具來輔助檢查。常見的效能熱點包括:
-
在列表場景中頻繁使用的 LadyForEach 元件,需要指定 key 以實現列表複用。如果開發者忘記指定 key,Code Linter 會報錯提示。
-
在 onClick 或 onVisible 等函式中編寫空 callback(回撥函式)。當這些空 callback 積累到一定數量(如幾百個或上千個)時,可能會嚴重拖慢應用效能。Code Linter 可以掃描出這類問題。
-
未使用 TaskPool 處理網路資源。例如,Image Bitmap 直接傳遞 URL 進行同步載入,當網路阻塞時會導致 UI 執行緒卡頓。
-
複雜的 ETS 元件在列表場景下未實現重用。未設定重用的 ETS 元件在列表滾動時需要重新構建,非常耗時。元件巢狀層級過深也會導致效能問題。在安卓端,佈局檢查器建議容器巢狀不超過四層。
-
使用 JSON.stringify 進行物件序列化。JSON.stringify 有一定耗時,尤其在處理 100KB 左右的資料時,可能需要 10 毫秒左右。Code Linter 會提示這部分效能問題,但是否需要轉非同步執行緒需要開發者自行判斷。
-
呼叫 Image 的 syncLoad(同步載入)。在某些場景下,如轉場動畫,需要同步載入 image 以保證連貫性。但如果 image 是非磁碟資源(如網路資源),會導致卡幀。Code Linter 可以掃描出這類問題。
-
關於編譯器的最佳化。ETS 元件應避免巢狀過深。如果巢狀過深,可以將每層函式透過系統的 builder param 或 builder 函式轉換。使用 @builder 註解標識的函式會在編譯期間與 ETS 程式碼整合,從而提高編譯器最佳化效果。
Code Linter 支援全量掃描和基於 Git DIFF 的增量掃描,但目前華為的 Code Linter 還不能與 Git Prehook 關聯,導致無法在流水線上自動檢查。雖然 CI 檢查階段已有 Code Linter,但原生代碼提交階段仍需手動執行指令碼,無法實現自動檢查。我們正在催促華為解決這一問題。

在處理 UI 過載場景時,我們採用了一種稱為分幀方案的方法。分幀這個術語的含義是,當應用在一幀內無法完成所有繪製工作,或者在多幀內都無法完成時,會導致螢幕卡頓現象。儘管使用者可以看到畫面,但卻無法進行滑動或操作。在這種情況下,分幀方案就顯得尤為合適。雖然分幀方案可能看起來不是最優雅的解決辦法,但它確實能夠有效地解決效能問題,使應用效能達到預期標準。分幀方案雖然看似是一種應急措施,但它能夠幫助應用效能達標。
分幀方案的流程大致如下:假設我們有資料 a、b、c 需要渲染,未採用分幀方案前,資料 a、b、c 會同時到達並觸發狀態變更,進而驅動整個 UI 進行重新整理。這會導致在一幀內需要繪製大量 UI 元件,從而影響應用效能。為了解決這個問題,我們採用分幀方案,將資料 a、b、c 拆分開,分別在不同的幀中進行渲染。例如,資料 a 在第一幀中渲染完成後,透過呼叫宏觀指令讓其進入下一階段,然後在下一幀中更新資料 b,依此類推。

在小紅書的圖文筆記場景中,分幀方案得到了應用。當用戶在首頁的雙列場景中點選一篇筆記進入筆記詳情頁時,這個過程涉及到許多元件的載入。我們可以將這些元件拆分成不同的幀,例如幀 a、幀 b 和幀 c。對於使用者而言,他們通常希望在第一時間看到整個大屏的畫面,因此我們會優先在幀 a 中展示大圖。而在幀 b 和幀 c 中,我們再處理頂部導航欄或底部互動區等內容。透過這種分幀策略,我們能夠確保使用者在第一時間看到最關鍵的內容,同時避免了因為一次性載入過多元件而導致的效能問題。

傳統的主觀工具對於鴻蒙 OS 的效能分析仍然適用。例如,抖音和小紅書都透過競品分析來進行主觀測評。這種能力主要是通過錄屏來展示整個流程的耗時和時長,特別適合評估冷啟動完成時延和轉場過程的效能。通過錄屏,我們可以逐幀檢視使用者從點選開始到結束的幀數和真即時長,以此來衡量整個過程的持續時間。
除了主觀工具,我們還可以使用 IDE 提供的效能分析工具,如 Profiler,來分析慢函式。由於 ArkTS 程式語言框架主要透過 RTS 和 NAPI(原生應用介面)進行關聯,因此需要能夠檢視 ArkTS 和 NAPI 的整個堆疊層級。這與安卓有所不同,因為當 Java 透過 Java Native API 與原生程式碼互動時,堆疊並不那麼容易檢視。
在小紅書的效能分析中,我們展示了一個整體執行緒分析的例子。在左側,可以看到小紅書的主執行緒(如 com 點開頭的執行緒)、Daemon 執行緒、Worker 執行緒以及 FFRT 執行緒。FFRT 是一種執行函式流的執行緒,可以執行 TaskPool 上的函式。在下圖右側,我們可以看到在 RTS 環境下的分析結果,其中頂部顯示了 NAPI 呼叫,底部則是一些 C++ 函式。整個呼叫棧和它們的執行時長是透過一種自上而下的檢視來展示的。利用這種檢視,我們可以精確地識別出哪些慢函式是造成介面卡頓的原因。

DevEco Testing 是一個性能測試工具,它的功能非常全面,效能測試只是其中的一部分。除了效能測試,它還支援多種測試場景,包括 debug testing。在 debug testing 場景中,使用者可以自定義業務場景,監測 CPU 的耗時和負載、GPU 的耗時和負載、裝置發熱情況以及功耗等問題。

使用 DevEco Testing 進行效能測試的過程如下:首先定義測試場景,然後捕獲主幀資料。一旦開始捕獲,就可以觀測到 FPS(幀率)、GPU 負載以及整體功耗等資料。完成效能資料捕獲後,工具會生成一份報告,為使用者提供了一個完整的場景分析。不過,目前場景定義還缺乏指令碼化能力,需要人工操作輔助。未來,我們期望能夠實現場景定義的指令碼化配置,類似於自動化測試。這樣,就可以透過自動化工具,實現更高效的測試流程。
在對效能場景進行最佳化後,我們可以看到顯著的收益。在實驗室環境下的測試顯示,冷啟動時間可以降低 50%,響應時延可以低於 100 毫秒,完成時延則保持與雙端持平或更優。在流暢性方面,在多場景和過載場景下均實現了 0 丟幀的成果。需要注意的是,這裡的測試是在非過載模式下進行的,即沒有同時執行多個資源密集型應用,如《王者榮耀》或《和平精英》等。在這種條件下,我們的核心場景,如冷啟動、搜尋和個人頁等,都能夠與雙端完全對齊。

展望未來,有幾個方向。首先,我們希望能夠在全場景下實現元件複用,以最大程度地實現 UI 複用。這樣可以在多個業務之間的轉場或 UI 建立過程中,將不必要的 UI 建立和消耗降到最低。其次,我們正在考慮程式碼延遲載入的 lazy 機制。華為內部可能將其作為通用的解決方案,但在實施過程中我們發現了許多問題,例如全 lazy 載入可能會影響第三方 SDK,如支付寶等,因為它們可能進行了額外的二進位制最佳化,導致載入失敗或無法響應。因此,我們期望透過程式碼延遲載入來實現持續治理,但目前它可能還不適合全場景的 lazy import。最後,我們關注防劣化問題,即在每個版本釋出時,我們不希望效能指標出現劣化。我們希望能夠在開發階段就定義劣化指標和具體資料,以防止應用劣化。這部分可能需要藉助 DevEco Testing 和主觀測評的方式來實現。包括我們關注的指標,例如冷啟動和流暢性等,未來可能會納入防劣化場景。目前,我們的 CI 環節或 RC 環節,包括流水線的效能管控和程式碼 CR 機制,都能夠規避這類問題。
王勁鵬,小紅書鴻蒙工程師。目前主要負責小紅書鴻蒙版的研發和工程建設,曾從事過大前端架構設計、研發效能等方向的工作,在終端架構演進、效能最佳化以及跨端容器和動態化等方面具備長期實踐及深厚經驗,持續關注大前端技術體系,鴻蒙以及多端的演進。
在 AI 大模型重塑軟體開發的時代,我們如何把握變革?如何突破技術邊界?4 月 10-12 日,QCon 全球軟體開發大會· 北京站 邀你共赴 3 天沉浸式學習之約,跳出「技術繭房」,探索前沿科技的無限可能。
本次大會將匯聚頂尖技術專家、創新實踐者,共同探討多行業 AI 落地應用,分享一手實踐經驗,深度參與 DeepSeek 主題圓桌,洞見未來趨勢。
