愛奇藝RND框架技術探索——架構與實現

愛奇藝技術產品團隊發表於2022-12-05

前言

RND,全稱React Node Desktop,起源於RN在愛奇藝PC端的實現,採用React JS framework +Node.js runtime + native UI engine架構,目標是成為最輕量的JS開發桌面應用的跨平臺方案。之前我們還分享了一篇關於RND的Native API注入技術的文章《搭建連線JS與C++的橋樑 - 愛奇藝RND框架之JS自動繫結》,大家可以參考

目前RND已經在愛奇藝PC客戶端大量應用,在最新的愛奇藝客戶端中,除了播放視窗和視窗邊框等部分採用C++開發外,其餘頻道頁均是基於RND框架採用Java Script開發的,RND無縫地將Native部分與Java Script開發的UI模組融合到一起,使用者從體驗上無法感知哪部分是C++開發,哪部分是Java Script開發的。RND的應用有效降低了開發難度和成本,提高了開發效率,同時也為產品迭代提供了更加多樣化的解決方案。

下面是RND在愛奇藝客戶端上應用的幾個場景:

  • 基於RND的頻道頁:

愛奇藝RND框架技術探索——架構與實現

  • 融合Native播放器的RND頁面:

愛奇藝RND框架技術探索——架構與實現

  • 播放器側邊欄資訊區:

愛奇藝RND框架技術探索——架構與實現

本文接下來將從技術選型執行緒模型JS執行時Bridge資源管理除錯支援等幾個方面對RND的實現作一個簡單的梳理,以期能夠讓大家對RND在Windows上的實現方案有一個較全面的瞭解。

技術選型與架構設計

RN最核心的部件當然是JavaScript引擎,毋庸置疑V8是RND的首選。對於UI部分的實現,在移動端,無論是安卓還是iOS,RN對接的都是原生的UI元件,熟悉Windows客戶端的開發者都知道,由於一些眾所周知的原因,現在基於Windows的網際網路產品的UI幾乎不會選擇原生的UI控制元件,很多大廠都開發了自己的UI庫。愛奇藝也有自己的UI渲染引擎——Lyra,Lyra是一套十分優秀的非同步渲染引擎,目前支援Windows和MAC OS兩個平臺,RND所有的UI渲染都是以Lyra作為基礎,並且RND還整合了Yoga佈局系統來實現UI Component的flex佈局計算。

在Native能力方面,因RND整合了Node執行時,這使得基於RND的JS開發者擁有了Node強大的Native基礎能力,開發者可以按需引入Node模組來擴充套件應用的Native能力;本地快取方面,RND採用了高效能的本地儲存系統LevelDB,LevelDB是一款效能十分優秀的Nosql資料庫,支援key/value形式的資料儲存;在除錯方面,RND除了支援Chrome外,還支援VSCode、Electron除錯,方便開發者按自己的需求進行除錯。

愛奇藝RND框架技術探索——架構與實現

RND架構圖

RND的執行緒模型

RND採用了UI執行緒和JS執行緒的雙執行緒模式,其中渲染命令和佈局都是在UI執行緒中完成的,RN JS的程式碼則是執行在JS執行緒中。RNJS框架生成渲染命令後,透過注入的互動函式傳送到UI執行緒中,UI執行緒收到命令進行解析,完成JS元件的建立、佈局和渲染。

當在UI執行緒中存在複雜任務時,RND的渲染仍然能保證介面繪製的流暢度,這要歸功於UI採用的非同步渲染引擎——Lyra,Lyra執行的雙執行緒渲染模式,UI執行緒會將paint訊息傳送到獨立的render執行緒執行,避免UI執行緒上的耗時計算阻塞介面繪製,因此,RND有著非常出色的渲染能力。

愛奇藝RND框架技術探索——架構與實現

RND執行緒模型

JS執行時的實現

在Windows平臺上,RND採用V8作為JavaScript引擎。JS執行時是對JS執行環境的抽象描述:隔離了不同平臺JS引擎的介面差異,為上層提供了統一的訪問介面,並向JS引擎注入了必要的Native API以支援RN的執行。同時,JS執行時還對外暴露了ReactJS的事件監聽介面和Native API注入框架。

封裝V8

愛奇藝RND框架技術探索——架構與實現

RND對JS執行時的抽象和封裝

考慮到記憶體與效能開銷,在同一程式中,所有RootView例項共享V8的同一個Isolate物件,而每一個RootView獨立擁有一個V8的Context,保證其執行環境的隔離。因共享Isolate的原因,所有的RootView共享同一個JS執行執行緒。共享執行緒也可以有效降低執行緒競爭。開發者也可以改變這一策略,根據實際資源使用情況來決定Isolate的數量。

Snapshot助力加速啟動過程

V8還有一個非常有用的特性為RND所用——Snapshot執行模式:Snapshot是將V8執行期某一時刻的執行快照轉儲到磁碟檔案中,當程式再次啟動時可以直接從儲存好的快照直接恢復到當時的執行狀態,這一特性可以有效幫助RND提升應用的啟動速度。

愛奇藝RND框架技術探索——架構與實現

使用snapshot啟動速度加快近300ms

整合Node執行時,引入Node生態

因為開源專案Node同樣使用了V8引擎,這樣我們做很少的工作就可以將Node引入到RND中了。RN開發者不但具有了本地檔案、網路等基礎Native訪問能力,而且還可以將Node的開發包整合到開發環境中來。

愛奇藝RND框架技術探索——架構與實現

RND同時支援RN和node的modules

一個典型的例子,在RND中Web Socket介面就是由Node來支援的。在Chrome、DevTools的除錯實現中都用到了Web Socket。

Bridge實現

Bridge的實現大概是RN原理介紹相關的文章中讀者最關心的部分了,與RN移動版本的實現不同,因RND基於C開發,而V8亦是以C向Native提供介面的,因此在實現Bridge時,RND不需要額外處理異構語言互動的問題。

互動實現

單介面、非同步互動的模式是RN實現Bridge的最大特點。RND對Bridge部分作了一些改良和擴充,對於UI以外的處理,RND將其從messageQueue中“拆了出來”,提供了直接的API來完成,比如timer、本地快取訪問、網路請求等Native模組。這些介面在Native端基本都是非同步介面,因此不會造成阻塞,但在執行邏輯處立刻呼叫會加速併發能力,以便定時器更加精確或網路請求更早將請求傳送出去。

愛奇藝RND框架技術探索——架構與實現

Bridge實現

Yoga佈局

Lyra系統目前並不支援Flexbox佈局規範,因此RND並沒有使用Lyra的佈局系統,而是與RN一樣採用了Facebook的Yoga佈局系統,Yoga支援Flexbox規範,是一款非常優秀的跨平臺佈局系統。相較於之前的版本,Yoga最佳化了Dirty演算法,只對發生位置或大小變化的相關控制元件進行Dirty,大大提高了繪製效率。

愛奇藝RND框架技術探索——架構與實現

RND應用介面佈局

RootView內部的控制元件接受Yoga佈局,其自身則與其他Lyraui控制元件接受Lyra的佈局。

RND的資源管理與熱更新

模組化資源管理

愛奇藝RND框架技術探索——架構與實現

RND資源管理

每一個Module對應了一個資源配置(ResourceConfig),這個資源配置對映了一個資源配置管理物件,透過這個資源配置管理物件便可獲取到當前要使用的資源型別和資源內容。

進行資源模組化,其實是Lyra ui本身的使用要求,因此,RND的資源模組化實際上是使用了Lyra ui的資源管理策略。

RND中,JS業務程式碼,圖片檔案都被視為資源,在釋出版本中,都被打包到zip中,在開發模式下,是以檔案形式存放在程式碼目錄中的,為了統一組織不同模式下的資源載入,RND抽象了ResLoader物件,負責載入不同型別的資源,同時,ResLoader還會呼叫熱更新模組進行資源zip包的升級。

圖片資源自動載入機制

愛奇藝RND框架技術探索——架構與實現圖片載入與顯示

RND UI元件的圖片資源有3種來源:網路、本地快取和zip資源包,存放在zip資源包的圖片資源一般都是較少更新的、較固定的圖片資源。大部分圖片是動態更新的,JS透過URL的形式來設定圖片資源屬性,RND根據URL的格式來區別圖片來自網路還是zip包,來自網路的圖片URL是一個http的URL,而zip包中的圖片則是一個檔名的形式。因此RND很容易區分這兩種圖片來源,當判斷是來自網路時,RND會首先檢查是否存在快取檔案,如果存在則直接讀取快取圖片。

可靈活配置的熱更新

RootView在初始化時ResLoader會透過ConfigManager獲取資源更新物件,呼叫UpdateResource函式進行資源更新,當資源有更新時便會直接載入新的資源包執行,如果不存在更新則載入預設的資源包。

愛奇藝RND框架技術探索——架構與實現

RootView資源熱更新

RND支援兩種資源更新策略,一種直接透過URL攜帶請求引數的方式請求升級資源包,另一種則是先拉取一個升級策略檔案,再透過讀取升級策略進行升級,可以透過ConfigManager由宿主程式指定。

使用者也可以實現自己的資源更新策略,在配置物件中指定,RND會優先使用自定義更新策略來更新資源。

除錯支援

工欲善其事必先利其器,在除錯方面,我們投入了大量的精力來完善增強RND的工具鏈,一方面我們比RN有更豐富的除錯工具;另一方面,我們創新性地整合了除錯與目標應用的JS執行時,除錯環境就是執行環境,所有與Native的呼叫都是真實呼叫,而不是委託給Web Socket實現的“偽呼叫”,這完美解決了在除錯模式下Native介面同步呼叫的問題,也提高了除錯的便利性,開發者可以在JS程式碼中同步跟蹤Native介面呼叫。

多樣化除錯支援

除了Chrome外,RND還整合了Electron、VSCode等除錯工具,開發者可以按照不同的需求或喜好可以選擇不同的除錯工具,RND推薦使用Electron或VSCode來除錯,Electron完全支援Chrome所有的除錯和效能分析功能,而VSCode則是JS開發者首選的IDE,在開發中進行除錯、熱更新都非常的方便。使用者可以透過除錯配置檔案選擇使用哪一種除錯工具作為預設偵錯程式。


愛奇藝RND框架技術探索——架構與實現

RND除錯工具鏈

   Native介面同步除錯支援

在Chrome除錯模式下,RN JS並不是執行在自身的JS引擎中,而是被執行在Chrome的JS引擎中,對Native Api的呼叫也是透過Web Socket來代理實現的,因此,在這種場景下,如果想要執行同步Native Api的呼叫是無法實現的。在RND中,因RN JS需要同步獲取宿主視窗位置大小等資訊,Native提供了對應的同步介面,在除錯模式下對這類同步介面的除錯就無法實現了。

RND在Electron和VSCode除錯模式中將JS執行時整合到了一起,讓RN JS與宿主應用的Native部分執行在同一個程式中,這樣就實現了Native API的同步呼叫,除錯模式和執行模式的互動方式保持了一致。

除錯效果圖樣

  • 透過DevTools檢視頁面佈局:

愛奇藝RND框架技術探索——架構與實現

  • 透過VSCode進行除錯:

愛奇藝RND框架技術探索——架構與實現

  • 透過Chrome進行除錯:

愛奇藝RND框架技術探索——架構與實現

小結

本文著重從Native框架的角度介紹了RND的技術選型和關鍵模組的實現原理,關於RN JS框架部分本文並未提及,後續會有專門的一篇文章《愛奇藝RND框架之JS Framework解析》來介紹,敬請關注。由於篇幅關係,RND的動畫系統、效能分析系統等很多技術文中並未涉及,希望後續有時間能與大家一起分享。

RND在愛奇藝客戶端的成功實踐表明,RN同樣適用於以運營內容為主的、迭代週期密集的網際網路桌面應用,JS非常適合UI和業務邏輯的快速開發。隨著各大JS引擎效能不斷的最佳化,很多大廠都推出了基於JS語言的輕量級高效能App應用框架,可以預測在不久的將來,以內容運營為主的桌面產品上,JS很快會成為最受開發者歡迎的語言之一

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945252/viewspace-2655609/,如需轉載,請註明出處,否則將追究法律責任。

相關文章