博客 / 詳情

返回

【uni-app&微信小程序&React Native】跨端原理初探

文章內容

  1. 以官方文檔為基礎,對uni-app的基礎框架(邏輯層、渲染層)、組件、API進行簡單地分析
  2. 以官方文檔為基礎,對微信小程序框架(邏輯層、視圖層)、運行時進行簡單地分析
  3. 以官方文檔為基礎,對React Native舊架構和新架構進行簡單地分析

1. uni-app編譯

  • 在web平台,將.vue文件編譯為js代碼。與普通的vue cli項目類似
  • 在微信小程序平台,編譯器將.vue文件拆分生成wxml、wxss、js等代碼
  • 在app平台,將.vue文件編譯為js代碼。進一步,如果涉及uts代碼:

    • 在Android平台,將.uts文件編譯為kotlin代碼
    • 在iOS平台,將.uts文件編譯為swift代碼

編譯器分vue2版和vue3版

  • vue2版:基於webpack實現
  • vue3版:基於Vite實現,性能更快

編譯器支持條件編譯,即可以指定某部分代碼只編譯到特定的終端平台。從而將公用和個性化融合在一個工程中。

2. uni-app運行時runtime

2.1 基礎框架

  • 在web和小程序上,不需要uni-app提供js引擎和排版引擎,直接使用瀏覽器和小程序的即可。但app上需要uni-app提供
  • App的js引擎:App-Android上,uni-app的js引擎是v8,App-iOS是jscore
  • App的渲染引擎:同時提供了2套渲染引擎,.vue頁面文件由webview渲染,原理與小程序相同;.nvue頁面文件由原生渲染,原理與react native相同。開發者可以根據需要自主選擇渲染引擎。

uni-app App 端內置了一個基於 weex 改進的原生渲染引擎,提供了原生渲染能力

  • 在 App 端,如果使用 vue 頁面,則使用 webview 渲染
  • 如果使用 nvue 頁面(native vue 的縮寫),則使用原生渲染
  • 一個 App 中可以同時使用兩種頁面,比如首頁使用 nvue,二級頁使用 vue 頁面,hello uni-app 示例就是如此

雖然 nvue 也可以多端編譯,輸出 H5 和小程序,但 nvue 的 css 寫法受限,所以如果你不開發 App,那麼不需要使用 nvue。

2.1.1 邏輯層和渲染層分離

在web平台,邏輯層(js)和渲染層(html、css),都運行在統一的webview裏。
但在小程序和app端,邏輯層和渲染層被分離了。

分離的核心原因是性能。過去很多開發者吐槽基於webview的app性能不佳,很大原因是js運算和界面渲染搶資源導致的卡頓。


不管小程序還是app,邏輯層都獨立為了單獨的js引擎,渲染層仍然是webview

app上也支持純原生渲染,使用.nvue文件

2.1.2 邏輯層詳解

邏輯層是運行在一個獨立的jscore裏的,它不依賴於本機的webview,所以一方面它沒有瀏覽器兼容問題,可以在Android4.4上跑es6代碼,另一方面,它無法運行window、document、navigator、localstorage等瀏覽器專用的js API。

jscore就是一個標準js引擎,標準js是可以正常運行的,比如if、for、各種字符串、日期處理等。js和瀏覽器的區別要注意區分開來。

image.png

  • 所謂瀏覽器的js引擎,就是jscore或v8的基礎上新增了一批瀏覽器專用API,比如dom;
  • node.js引擎,則是v8基礎上補充一些電腦專用API,比如本地io;
  • 那麼uni-app的App端和小程序端的js引擎,其實是在jscore上補充了一批手機端常用的JS API,比如掃碼。

2.1.3 渲染層詳解

h5和小程序平台,以及app-vue,視圖層是webview,即.vue文件都會被渲染為WebView

app-nvue的視圖層是基於weex改造的原生渲染視圖,即.nvue文件會被改造為APP原生組件

兼容性

在iOS上,只能使用iOS提供的Webview(默認是WKWebview)。它有一定的瀏覽器兼容問題,iOS版本不同,它的表現有細微差異(一般可忽略)。

在Android上,小程序大多自帶了一個幾十M的chromium webview,而App端沒辦法帶這麼大體積的三方包,因此uni-app默認使用了Android system webview,這個系統webview跟隨手機不同而有差異

在Android上,App端也支持使用騰訊X5引擎,這樣就統一版本,儘可能減少兼容性問題

2.1.4 邏輯層和渲染層小結

邏輯層: js基本沒有不同手機的兼容問題(因為js引擎自帶了)

渲染層: 在app-vue上使用系統webview時會有手機瀏覽器的css兼容問題。此時或者不要用太新的css語法,或者集成騰訊x5引擎。

2.1.5 邏輯層和渲染層分離的利與弊

邏輯層和視圖層分離,好處是js運算不卡渲染,最簡單直接的感受就是:窗體動畫穩。

如果開發者使用過App,應該有概念,webview新窗體一邊做進入動畫,一邊自身渲染,很容易卡動畫。而uni-app則無需寫預載代碼,新窗體渲染快且動畫穩定。

但是兩層分離也帶來一個壞處,這兩層互相通信,其實是有損耗的。

iOS還好,但Android低端機上,每次通信都要耗時幾十毫秒。平時看不出來影響,但有幾個場景表現明顯:

  1. 連續高幀率繪製canvas動畫,會發現還不如webview內部繪製流暢
  2. 視圖層滾動、跟手操作,不停反饋給邏輯層,js再處理邏輯並通知視圖層做對應更新。此時會發現交互不跟手或卡頓

不管小程序還是app,不管app-vue還是app-nvue,都有這個兩層通信損耗的問題。

2.1.6 邏輯層和渲染層分離後進行的性能提升方法

在webview中,提供了一種運行於視圖層的專屬js,微信叫做wxs。uni-app支持把wxs編譯到微信小程序、App和H5中,而且在wxs的基礎上進行增強:

  • 微信裏對wxs限制較多,只能實現有限的功能。
  • app端提供了更強大的renderjs,併兼容到H5平台,比如canvas動畫,微信的canvas無法通過wxs操作,js不停繪製canvas動畫因通信折損而無法流暢。uni-app的app-vue裏的canvas對象設計在webview視圖層的,通過renderjs可以在視圖層直接操作canvas動畫,將不再有通信折損,實現更流暢的效果

在原生渲染的視圖層(app-nvue),邏輯層和視圖層的折損一樣存在。包括react native也有這個問題,weex提供了一套bindingx機制,可以在js裏一次性傳一個表達式給原生層,由原生層解析後根據指令操作原生的視圖層,避免反覆跨層通信。這個技術在uni-app裏也可以使用。

bindingx作為一種表達式,它的功能不及js強大,但手勢監聽、動畫還是可以實現的,比如uni ui的swiperAction組件在app-nvue下運行時會自動啓用bindingx,以實現流暢跟手。

2.2 組件

為了降低開發者的學習成本,uni-app的內置基礎組件命名規範與小程序基本相同。

runtime中包括的組件只有基礎組件,如<view>、<button>等。為了減少包體積,擴展組件不包含在uni-app的runtime中,而是下載到用户的項目代碼中(這些組件都是vue組件),讓用户自己按需使用這些擴展組件

在小程序端,uni-app基礎組件會直接轉義為小程序自己的內置組件。在小程序的runtime中不佔體積。在web和android、iOS端,這幾十個組件都在uni-app的runtime中,會佔用一定體積,相當於內置了一套ui庫。

2.3 API

主要分為:

  • 小程序平台:uni對象會轉為小程序的自有對象,比如在微信小程序平台,編寫uni.request等同於wx.request。那麼所有wx.的API都可以這樣使用。
  • web平台:window、dom等瀏覽器專用API仍可以使用
  • app平台:除了uni.的API,還可以使用plus.的API、Native.js,以及通過uts編寫原生插件,或者使用java和objectC編寫原生插件。這些原生插件調用os的API並封裝給js使用。

uni-app不限制各端原生平台的API調用。開發者可以在uni-app框架中無限制的調用該平台所有能使用的API。即,

  • 在小程序平台,小程序的所有API都可以使用;
  • 在web平台,瀏覽器的所有API都可使用;
  • 在iOS和Android平台,os的所有API都可以使用。

在上面的2.1 基礎框架的分析中,我們知道
App的渲染提供了2套渲染引擎:

  • .vue頁面文件由webview渲染,原理與小程序相同
  • .nvue頁面文件由原生渲染,原理與react native相同

接下來我們將針對小程序和react native的原理展開分析


3. 微信小程序底層原理

3.1 框架

整個小程序框架系統分為兩部分:邏輯層(App Service)和 視圖層(View)。小程序提供了自己的視圖層描述語言 WXMLWXSS,以及基於 JavaScript 的邏輯層框架,並在視圖層與邏輯層間提供了數據傳輸和事件系統,讓開發者能夠專注於數據與邏輯。

小程序採用 AppService 和 WebView 的雙線程模型,渲染層的界面使用 WebView 進行渲染;邏輯層採用 JSCore 運行 JavaScript 代碼
基於 WebView 和原生控件混合渲染的方式,小程序還優化擴展了 Web 的基礎能力,保證了在移動端上有良好的性能和用户體驗

Skyline渲染引擎Beta

Skyline渲染引擎瞭解下即可,目前還處於測試階段,本文還是將重點放在WebView模式下

Web 技術至今已有 30 多年曆史,作為一款強大的渲染引擎,它有着良好的兼容性和豐富的特性。 儘管各大廠商在不斷優化 Web 性能,但由於其繁重的歷史包袱和複雜的渲染流程,使得 Web 在移動端的表現與原生應用仍有一定差距。
為了進一步優化小程序性能,提供更為接近原生的用户體驗,微信小程序在 WebView 渲染之外新增了一個渲染引擎 Skyline,其使用更精簡高效的渲染管線,並帶來諸多增強特性,讓 Skyline 擁有更接近原生渲染的性能體驗。

在 Skyline 環境下,Skyline 創建了一條渲染線程來負責 Layout, Composite 和 Paint 等渲染任務,並在 AppService 中劃出一個獨立的上下文,來運行之前 WebView 承擔的 JS 邏輯、DOM 樹創建等邏輯。這種新的架構相比原有的 WebView 架構,有以下特點:

  • 界面更不容易被邏輯阻塞,進一步減少卡頓
  • 無需為每個頁面新建一個 JS 引擎實例(WebView),減少了內存、時間開銷
  • 框架可以在頁面之間共享更多的資源,進一步減少運行時內存、時間開銷
  • 框架的代碼之間無需再通過 JSBridge 進行數據交換,減少了大量通信時間開銷
Skyline渲染引擎能很好地保持和原有架構的兼容性,基於 WebView 環境的小程序代碼基本上無需任何改動即可直接在新的架構下運行。但是WXS 被移到 AppService 中,雖然邏輯本身無需改動,但詢問頁面信息等接口會變為異步,效率也可能有所下降;為此,我們同時推出了新的 Worklet 機制,用以高性能地構建各種複雜的動畫效果。

新的渲染流程如下圖所示:
design.3c2a69c4.png

3.1.1 邏輯層

小程序開發框架的邏輯層使用 JavaScript 引擎為小程序提供開發 JavaScript 代碼的運行環境以及微信小程序的特有功能。
邏輯層將數據進行處理後發送給視圖層,同時接受視圖層的事件反饋。

開發者寫的所有代碼最終將會打包成一份 JavaScript 文件,並在小程序啓動的時候運行,直到小程序銷燬。

JavaScript 的基礎上,微信小程序增加了一些功能,以方便小程序的開發:

  • 增加 AppPage 方法,進行程序註冊和頁面註冊。
  • 增加 getAppgetCurrentPages 方法,分別用來獲取 App 實例和當前頁面棧。
  • 提供豐富的 API,如微信用户數據,掃一掃,支付等微信特有能力。
  • 提供模塊化能力,每個頁面有獨立的作用域。
注意:小程序框架的邏輯層並非運行在瀏覽器中,因此 JavaScript 在 web 中一些能力都無法使用,如 window,document 等。

3.1.2 視圖層

框架的視圖層由 WXML 與 WXSS 編寫,由組件來進行展示。
將邏輯層的數據反映成視圖,同時將視圖層的事件發送給邏輯層。

  • WXML(WeiXin Markup language) 用於描述頁面的結構。
  • WXS(WeiXin Script) 是小程序的一套腳本語言,結合 WXML,可以構建出頁面的結構。
  • WXSS(WeiXin Style Sheet) 用於描述頁面的樣式。
  • 組件(Component)是視圖的基本組成單元。

3.1.3 雙線程模型架構

小程序的邏輯層和渲染層是分開的兩個線程。在渲染層,宿主環境會把WXML轉化成對應的JS對象,在邏輯層發生數據變更的時候,我們需要通過宿主環境提供的setData方法把數據從邏輯層傳遞到渲染層,再經過對比前後差異,把差異應用在原來的Dom樹上,渲染出正確的UI界面

由於WebView 的 JS 邏輯、DOM 樹創建、CSS 解析、樣式計算、Layout、Paint (Composite) 都發生在同一線程。在 WebView 上執行過多的 JS 邏輯可能阻塞渲染,導致界面卡頓。

下載 (1).png
小程序邏輯層和渲染層的通信會由 Native (微信客户端)做中轉,邏輯層發送網絡請求也經由 Native 轉發。

為什麼要使用Hybrid技術來渲染微信小程序呢?

一般來説,渲染界面的技術有三種:

  1. 用純客户端原生技術來渲染
  2. 用純 Web 技術來渲染
  3. 介於客户端原生技術與 Web 技術之間的,互相結合各自特點的技術(下面統稱 Hybrid 技術)來渲染

由於小程序的宿主是微信,所以不太可能用純客户端原生技術來編寫小程序 。如果這麼做,那小程序代碼需要與微信代碼一起編包,跟隨微信發版本,這種方式跟開發節奏必然都是不對的。因此,微信小程序需要像Web 技術那樣,有一份隨時可更新的資源包放在雲端,通過下載到本地,動態執行後即可渲染出界面。

但是,如果微信小程序用純 Web 技術來渲染小程序,在一些有複雜交互的頁面上可能會面臨一些性能問題,這是因為在 Web 技術中,UI渲染跟 JavaScript 的腳本執行都在一個單線程中執行,這就容易導致一些邏輯任務搶佔UI渲染的資源。

因此,最終選擇了兩者結合起來的 Hybrid 技術來渲染小程序。

Hybrid 技術在業界過去幾年裏演化過數種技術方案:典型的如早期的PhoneGap,還有近幾年流行的React Native(下稱 RN),還有像微信網頁裏的 JS-SDK這種輕量級的應用
為什麼要不使用React Native這樣技術作為微信小程序的技術選型呢?

微信小程序最終沒有選擇類RN作為微信小程序的技術選型,那是因為:

  1. RN 所支持的樣式是 CSS 的子集,會滿足不了 Web 開發者日漸增長的需求,而對 RN 的改造具有不小的成本和風險。
  2. RN 現有能力下還存在的一些不穩定問題,比如性能、Bug等。RN 是把渲染工作全都交由客户端原生渲染,實際上一些簡單的界面元素使用 Web 技術渲染完全能勝任,並且非常穩定。
  3. RN 存在一些不可預期的因素,比如近期就出現了許可協議問題。

因此微信小程序最終選擇了類似於微信 JSSDK 這樣的 Hybrid 技術,即界面主要由成熟的 Web 技術渲染,輔之以大量的接口提供豐富的客户端原生能力:

  • 每個小程序頁面都是用不同的WebView去渲染,這樣可以提供更好的交互體驗,更貼近原生體驗,也避免了單個WebView的任務過於繁重
  • 界面渲染定義了一套內置組件以統一體驗,並且提供一些基礎和通用的能力
  • 內置組件有一部分較複雜組件是用客户端原生渲染的,以提供更好的性能

3.1.4 組件系統

視圖層的組件系統

小程序的視圖是在WebView裏渲染的,那搭建視圖的方式自然就需要用到HTML語言。如果我們直接提供HTML的能力,那前面章節所介紹的為解決管控與安全而建立的雙線程模型就成為擺設了。開發者可以利用A標籤實現跳轉到其它在線網頁,也可以動態執行JavaScript等。除管控與安全外,還有一些的不足之處:

  • 標籤眾多,增加理解成本;
  • 接口底層,不利於快速開發;
  • 能力有限,會限制小程序的表現形式。

因此,微信小程序設計一套組件框架——Exparser。
基於這個框架,內置了一套組件,以涵蓋小程序的基礎功能,便於開發者快速搭建出任何界面。同時也提供了自定義組件的能力,開發者可以自行擴展更多的組件,以實現代碼複用。

3.1.5 原生組件

在內置組件中,有一些組件較為特殊,它們並不完全在Exparser的渲染體系下,而是由客户端原生參與組件的渲染,這類組件我們稱為“原生組件”,這也是小程序Hybrid技術的一個應用。
引入原生組件主要有3個好處:

  1. 擴展Web的能力。比如像輸入框組件(input, textarea)有更好地控制鍵盤的能力。
  2. 體驗更好,同時也減輕WebView的渲染工作。比如像地圖組件(map)這類較複雜的組件,其渲染工作不佔用WebView線程,而交給更高效的客户端原生處理。
  3. 繞過setData、數據通信和重渲染流程,使渲染性能更好。比如像畫布組件(canvas)可直接用一套豐富的繪圖接口進行繪製。
常用的原生組件有:video、map、canvas、picker

交互比較複雜的原生組件都會提供“context”,用於直接操作組件。以canvas為例,小程序提供了wx.createCanvasContext方法來創建canvas的context。這是一個可以用於操作canvas的對象,對象下提供了很多繪圖的方法,如“setFillStyle”方法可以設置填充樣式,“fillRect”方法用於繪製矩形

原生組件脱離在WebView渲染流程外,這帶來了一些限制。最主要的限制是一些CSS樣式無法應用於原生組件,例如,不能在父級節點使用overflow:hidden來裁剪原生組件的顯示區域;不能使用transformrotate讓原生組件產生旋轉等

3.2 運行時

微信小程序運行在多種平台上:iOS/iPadOS 微信客户端、Android 微信客户端、Windows PC 微信客户端、Mac 微信客户端、小程序硬件框架和用於調試的微信開發者工具等。

不同運行環境下,腳本執行環境以及用於組件渲染的環境是不同的,性能表現也存在差異:

  • 在 iOS、iPadOS 和 Mac OS 上,小程序邏輯層的 JavaScript 代碼運行在 JavaScriptCore 中,視圖層是由 WKWebView 來渲染的,環境有 iOS 14、iPad OS 14、Mac OS 11.4 等;
  • 在 Android 上,小程序邏輯層的 JavaScript 代碼運行在 V8 中,視圖層是由基於 Mobile Chromium 內核的微信自研 XWeb 引擎來渲染的;
  • 在 Windows 上,小程序邏輯層 JavaScript 和視圖層都是用 Chromium 內核;
  • 在 開發工具上,小程序邏輯層的 JavaScript 代碼是運行在 NW.js 中,視圖層是由 Chromium Webview 來渲染的。

3.2.1 JavaScript 支持情況

  • 小程序中不支持動態執行 JS 代碼,即使用 eval 執行 JS 代碼或者使用new Function創建函數
  • 標準 ECMAScript 支持,微信小程序內置了一份 core-jsPolyfill。core-js 可以將平台環境缺失的標準 API 補齊。
需要注意的是,平台對 ECMAScript 語法的支持差異無法抹平,當你需要使用一些高級語法時,如 async/await 時,則需要藉助 代碼轉換工具 來支持這些語法。
  • 無法支持一些無法被 Polyfill 的 API,比如Proxy 對象
注:由於實現原因與 iOS JavaScriptCore 限制,iOS 環境下的 Promise 是一個使用 setTimeout 模擬的 Polyfill。這意味着 Promise 觸發的任務為普通任務,而非微任務,進而導致 在 iOS 下的 Promise 時序會和標準存在差異

3.2.2 小程序的運行機制

life-cycle.5558d9eb.svg

  • 冷啓動:如果用户首次打開,或小程序銷燬後被用户再次打開,此時小程序需要重新加載啓動,即冷啓動。
如果用户已經打開過某小程序,然後在一定時間內再次打開該小程序,此時小程序並未被銷燬,只是從後台狀態進入前台狀態,這個過程就是熱啓動。
從小程序生命週期的角度來看,我們一般講的「啓動」專指冷啓動,熱啓動一般被稱為後台切前台。
  • 小程序啓動後,界面被展示給用户,此時小程序處於「前台」狀態。
  • 當用户「關閉」小程序時,小程序並沒有真正被關閉,而是進入了「後台」狀態,此時小程序還可以短暫運行一小段時間,但部分 API 的使用會受到限制。

切後台的方式包括但不限於以下幾種:

  • 點擊右上角膠囊按鈕離開小程序
  • iOS 從屏幕左側右滑離開小程序
  • 安卓點擊返回鍵離開小程序
  • 小程序前台運行時直接把微信切後台(手勢或 Home 鍵)
  • 小程序前台運行時直接鎖屏
  • 小程序進入「後台」狀態一段時間後(目前是 5 秒),微信會停止小程序 JS 線程的執行,小程序進入「掛起」狀態。此時小程序的內存狀態會被保留,但開發者代碼執行會停止,事件和接口回調會在小程序再次進入「前台」時觸發。
當開發者使用了後台音樂播放、後台地理位置等能力時,小程序可以在「後台」持續運行,不會進入到「掛起」狀態
  • 小程序銷燬:如果用户很久沒有使用小程序,或者系統資源緊張,小程序會被「銷燬」,即完全終止運行。

具體而言包括以下幾種情形:

  • 當小程序進入後台並被「掛起」後,如果很長時間(目前是 30 分鐘)都未再次進入前台,小程序會被銷燬。
  • 當小程序佔用系統資源過高,可能會被系統銷燬或被微信客户端主動回收。

4. React Native原理

從 0.68 版本開始,React Native 提供了新架構,它為開發者提供了構建高性能和響應式應用的新功能。

4.1 舊架構

下面架構圖來自Deep dive into React Native’s New Architecture

1_0LTWA_egTnRLRlqXoRUymg.webp

4.1.1 三線程

React Native主要有3個線程:

  • JavaScript Thread:Metro(打包工具)將React源碼打包成JS Bundle文件,然後傳入JavaScriptCore引擎進行執行
  • Native/UI Thread:負責原生UI渲染Native UI和調用原生API能力Navite Module(比如藍牙、照相機等)
  • Shadow Thread:創建Shadow Tree模擬React結構樹,用於在將元素渲染到主機屏幕之前計算元素的佈局

4.1.2 Bridge

JS ThreadUI Thread之間的通信稱為Bridge,通過Bridge發送數據時,有幾個特點:

  • 批處理:對Native調用進行排隊,批量處理
  • 序列化:通過JSON格式來傳遞消息,每次都要經歷序列化和反序列化
  • 異步:消息隊列是異步的

即通過Bridge發送數據時,必須對其進行批處理(優化)並序列化為 JSON

4.1.3 JavaScriptCore

JavaScriptCore是一個JS引擎,IOS系統自帶了該引擎。為了統一Android和IOS使用同一個JavaScriptCore,React Native會將JavaScriptCore和app打包在一起,

  • 從 React Native 0.70 版本開始,React Native 會默認使用Hermes引擎,它是專門為 React Native 而優化的一個新式開源 JavaScript 引擎。
  • 如果 Hermes 被禁用或是較早的 React Native 版本,則會使用JavaScriptCore,也就是 Safari 所使用的 JavaScript 引擎。但是在 iOS 上 JavaScriptCore 並沒有使用即時編譯技術(JIT),因為在 iOS 中應用無權擁有可寫可執行的內存頁(因此無法動態生成代碼)。
  • 在使用 Chrome 調試時,所有的 JavaScript 代碼都運行在 Chrome 中,並且通過 WebSocket 與原生代碼通信。此時的運行環境是V8 引擎。(社區也有提供可以在生產環境中使用的react-native-v8)
從 0.68 版本開始,React Native 提供了新架構,它為開發者提供了構建高性能和響應式應用的新功能。因此從 0.70 版本開始,會使用Hermes引擎

4.1.4 Yoga

它是佈局引擎的名稱,用於計算用户屏幕的 UI 元素的位置

4.1.5 渲染流程淺析

  1. 佈局使用React編寫,轉化為Virtual DOM Tree後,JavaScript Thread使用Bridge發送序列化的JSON數據給Native/UI Thread,告訴它如何創建或者更新原生UI
  2. 這個時候Native/UI Thread會將數據發送給Shadow ThreadShadow Thread通過維護一個 Shadow TreeShadow Tree 可以理解為是 Virtual DOM TreeNative 的映射,擁有和 Virtual DOM Tree 相同的樹形層級關係)來計算 Virtual DOM TreeNative 頁面的實際佈局
  3. 計算完成後Shadow Thread返回數據異步通知Native/UI Thread進行創建或者更新原生UI
React Native不適合繪製特別複雜的界面以及複雜的動畫,效果比不上原生的效果

4.2 新的架構

從 0.68 版本開始,React Native 提供了新架構,它為開發者提供了構建高性能和響應式應用的新功能。

下面架構圖來自Deep dive into React Native’s New Architecture

1_FSQREEbL1-alhSP-fH4Nxg.webp

4.2.1 舊架構的問題

舊的架構曾經通過使用一個叫做橋(Bridge)的組件將所有必須從 JS 層傳遞到本地層的數據序列化來工作。橋可以被想象成一條總線,生產者層為消費者層發送一些數據。消費者可以讀取數據,將其反序列化並執行所需的操作。
橋有一些固有的限制:

  • 它是異步的:某個層將數據提交給橋,再異步地"等待"另一個層來處理它們,即使有時候這並不是真正必要的。
  • 它是單線程的:JS 是單線程的,因此發生在 JS 中的計算也必須在單線程上進行。
  • 它帶來了額外的開銷:每當一個層必須使用另一個層時,它就必須序列化一些數據。另一層則必須對其進行反序列化。這裏選擇的格式是 JSON,因為它的簡單性和人的可讀性,但儘管是輕量級的,它也是有開銷的。

4.4.2 新架構的改進

新架構放棄了"橋"的概念,轉而採用另一種通信機制:JavaScript 接口(JSI)。JSI 是一個接口,允許 JavaScript 對象持有對 C++ 的引用,反之亦然。

一旦一個對象擁有另一個對象的引用,它就可以直接調用該對象的方法。例如一個 C++ 對象現在可以直接調用一個 JavaScript 對象在 JavaScript 環境中執行一個方法,反之亦然。

這個想法可以帶來幾個好處:

  • 同步執行:現在可以同步執行那些本來就不應該是異步的函數。
  • 併發:可以在 JavaScript 中調用在不同線程上執行的函數。
  • 更低的開銷:新架構不需要再對數據進行序列化/反序列化,因此可以避免序列化的開銷。
  • 代碼共享:通過引入 C++,現在有可能抽象出所有與平台無關的代碼,並在平台之間輕鬆共享它。
  • 類型安全:為了確保 JS 可以正確調用 C++ 對象的方法,反之亦然,因此增加了一層自動生成的代碼。這些代碼必須通過 Flow 或 TypeScript 類型化的 JS 規範來生成。

參考文章

  1. 跨端框架一些原理分析
  2. React-Native — 原理探究
  3. 微信小程序官方文檔
  4. uni-app官方文檔
  5. React Native架構對比
  6. React Native 技術詳解 (一) - 認識它
  7. Deep dive into React Native’s New Architecture
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.