React跨端動(dòng)態(tài)化之從JS引擎到RN落地詳解
一 為什么跨端動(dòng)態(tài)化迫在眉睫
目前很多互聯(lián)網(wǎng)大廠的移動(dòng)端開發(fā)都在朝著跨端動(dòng)態(tài)化方向發(fā)展。由于快速迭代開發(fā)或者對(duì)原生包體積要求嚴(yán)格,及其對(duì)資源成本的把控,實(shí)現(xiàn)跨端動(dòng)態(tài)化迫在眉睫。我們先來看看 Native 原生開發(fā)的一些不足之處:
- 1 原生開發(fā)周期時(shí)間長(zhǎng),審核周期長(zhǎng),會(huì)影響到需求發(fā)布和迭代效率,有些場(chǎng)景下會(huì)更加棘手,比如修復(fù)線上緊急 bug ,或者是頻繁迭代一些開發(fā)需求。
- 2 目前移動(dòng)端主要的平臺(tái)就是 Android 和 iOS,如果一款前端應(yīng)用想要同時(shí)運(yùn)行在兩個(gè)平臺(tái)的話,采用 Native 就需要雙端各自開發(fā)一遍,這樣無疑浪費(fèi)了資源和提高了維護(hù)成本。
- 3 Native 開發(fā)代碼要打包在客戶端包中,這樣增加了包的體積,用戶下載的時(shí)候,會(huì)下載更多的資源,輕量級(jí)的包會(huì)提高運(yùn)營效率,而且 Android 和 iOS 應(yīng)用平臺(tái)也對(duì)包體積嚴(yán)格把控。
說到跨端化方案,首先想到的就是 React Native,為什么這么說呢? 我們往下看。
二 首當(dāng)其沖的為什么是 React Native
React 在跨端領(lǐng)域也有一席之地,功勞來源跨端方案 React Native,簡(jiǎn)稱 RN ,RN 是目前主流的動(dòng)態(tài)化方案之一,是 Facebook 在 2015 年開源的 JS 框架 React 在原生移動(dòng)應(yīng)用平臺(tái)的跨平臺(tái)技術(shù),支持安卓和 iOS 平臺(tái)。
RN 的受歡迎并不僅僅是支持安卓和 iOS 平臺(tái),還有一個(gè)重要的因素就是動(dòng)態(tài)化,那么這種動(dòng)態(tài)化相比于原生客戶端有什么優(yōu)點(diǎn)呢?
RN 對(duì)于原生開發(fā)有著明顯的優(yōu)點(diǎn):
- 1 RN 是采用運(yùn)行 React 的 JS 作為開發(fā)平臺(tái),這樣可以讓 web 開發(fā)者也能夠參與到 Native 開發(fā)中來,還有就是 RN 讓一套代碼可以運(yùn)行在兩端,大大減少了開發(fā)和維護(hù)成本。
- 2 RN 是采用原生渲染的,性能和體驗(yàn)僅次于 Native 開發(fā)。
- 3 還有一點(diǎn)也是最重要的,就是 RN 是動(dòng)態(tài)化的方案,也就是 RN 打出來的應(yīng)用包,并不是和 Native 包綁定在一起發(fā)布的,而是在運(yùn)行 Native 的時(shí)候拉下 RN 的包,這樣一是減少了 Native 包體積,二是 RN 包可以隨時(shí)發(fā)布,提高了迭代效率,也讓一些線上問題能夠快速解決。
近兩年,也有一些興起的跨端技術(shù)方案,比如 Flutter,阿里巴巴開源的 Rax 等,相比這些動(dòng)態(tài)化方法,RN 也有一定優(yōu)勢(shì):
- 1 生態(tài)成熟,技術(shù)社區(qū)活躍,采用 React 語法,學(xué)習(xí)成本低。
- 2 目前業(yè)界已經(jīng)出現(xiàn)了很多成熟方案,比如京東的 JDReact 和美團(tuán)的 MRN 等。
RN 是基于 React 框架開發(fā)的原生應(yīng)用,React 憑借著 JSX 語法讓使用者結(jié)合多種設(shè)計(jì)模式使開發(fā)變得非常靈活,React 是 JavaScript (簡(jiǎn)稱 JS ) 框架,那么如果想要運(yùn)行 RN ,那么就需要運(yùn)行 JS ,在我們的影響中,JS 作為腳本語言運(yùn)行到瀏覽器端,或者運(yùn)行在 Node.js 中,那么如今卻能夠作為跨端方案運(yùn)行到 Native 應(yīng)用中,這是為什么呢?
原來能夠讓 JS 運(yùn)行到 Native 中的法寶就是 JS 引擎,最常見的 JS 引擎就是 v8 ,v8 使用在 Chrome 瀏覽器和 Node.js 中,構(gòu)建了 JS 運(yùn)行時(shí),能夠執(zhí)行 JS 腳本。那么接下來我們就來看一下 RN 中的 JS 引擎。
三 JS 引擎讓跨端動(dòng)態(tài)化成為可能
V8 引擎簡(jiǎn)介
計(jì)算機(jī)本身并不能讀懂編程語言,計(jì)算機(jī)只能讀懂二機(jī)制文件,但是為了能夠讓編程語法能夠讓計(jì)算機(jī)讀懂,就必須編譯成二機(jī)制文件,這就是編譯語言,比如 JAVA GO 等都是編譯型的語言,編譯型語法在編譯成二機(jī)制文件后,會(huì)保存二機(jī)制文件,在運(yùn)行時(shí)候,可以直接運(yùn)行二機(jī)制文件,不需要重復(fù)編譯。
還有一類語言,不需要編譯成文件,而是需要通過解釋器對(duì)語言進(jìn)行動(dòng)態(tài)解釋和執(zhí)行,這類語言就是解釋型語言,比如 Python,JS 等。如下圖就是兩種類型的語言執(zhí)行過程:
編譯型語言啟動(dòng)需要編譯成二進(jìn)制文件,所以啟動(dòng)速度會(huì)比很慢,但是執(zhí)行的時(shí)候是直接使用編譯好的二進(jìn)制文件,所以執(zhí)行速度會(huì)快一些。
但是相比解釋型語言,啟動(dòng)會(huì)很快,但是執(zhí)行時(shí)候,需要通過解釋器解析語法樹,變成中間代碼,執(zhí)行字節(jié)碼,這樣就浪費(fèi)了時(shí)間,使得執(zhí)行速度會(huì)變慢。
由于 JS 是解釋型語言,它的執(zhí)行需要宿主環(huán)境提供,轉(zhuǎn)成語法樹 ,并且讀懂語法樹,轉(zhuǎn)成字節(jié)碼并執(zhí)行的能力,v8 引擎的工作就需要有這些能力:
Parser:將 JS 源碼轉(zhuǎn)換成抽象語法樹,什么是抽象語法?在計(jì)算機(jī)科學(xué)中,抽象語法樹(abstract syntax tree 或者縮寫為 AST),或者語法樹(syntax tree),是源代碼的抽象語法結(jié)構(gòu)的樹狀表現(xiàn)形式,這里特指編程語言的源代碼。
Lgniton:interpreter 解釋器,負(fù)責(zé)將 AST 轉(zhuǎn)換成指令字節(jié)碼,解釋執(zhí)行指令字節(jié)碼(ByteCode),解釋器執(zhí)行的時(shí)候主要有四個(gè)模塊:內(nèi)存中的字節(jié)碼,寄存器,棧和堆。
TurboFan:compiler 編譯器,通過 Lgniton 收集的信息,將指令字節(jié)碼轉(zhuǎn)換成優(yōu)化匯編代碼。
Orinoco:garbage collector 簡(jiǎn)稱 GC,垃圾回收模塊,負(fù)責(zé)將程序不需要的內(nèi)存空間回收,提升引擎性能。
如上還有一個(gè)問題就是如果每一次都通過 TurboFan 將指令字節(jié)碼轉(zhuǎn)換成匯編代碼,那么這樣十分浪費(fèi)性能。在 v8 出現(xiàn)之前,所有的 JS 虛擬機(jī)所采用的都是解釋執(zhí)行的方式,這是 JS 執(zhí)行速度過慢的主要原因之一。
而 v8 率先引入了即時(shí)編譯(JIT)的雙輪驅(qū)動(dòng)的設(shè)計(jì)(混合使用編譯器和解釋器的技術(shù)),這是一種權(quán)衡策略,給 JS 的執(zhí)行速度帶來了極大的提升。
那么 JIT 就是取編譯執(zhí)行語言和解釋執(zhí)行語言的長(zhǎng)處,利用解釋器對(duì)代碼進(jìn)行處理,對(duì)于頻率高的代碼進(jìn)行熱區(qū)收集,在之后指令字節(jié)碼編譯成機(jī)器碼的時(shí)候,儲(chǔ)存高頻率的二機(jī)制機(jī)器碼,之后就可以復(fù)用并執(zhí)行二機(jī)制代碼,以減少解釋器和編譯器的壓力。
v8 通過優(yōu)化后的工作流程如下:
知道了 v8 JS 引擎的工作流程之后,那么 RN 應(yīng)用中用什么 JS 引擎呢?
RN 在 0.60 版本之前使用 JSCore 作為默認(rèn)的 JS 引擎, JSCore 全名 JavaScriptCore ,JSCore 是 WebKit 默認(rèn)內(nèi)嵌的 JS 引擎,JSCore作為一個(gè)系統(tǒng)級(jí) Framework 被蘋果提供給開發(fā)者,作為蘋果的瀏覽器引擎 WebKit 中重要組成部分。
所以在 iOS 應(yīng)用中默認(rèn)為 JSCore 引擎,這使得 RN 也用 JSCore ,但是 JSCore 沒有對(duì) Android 機(jī)型做好適配,在性能,體積,和內(nèi)存上和 v8 有著明顯的差別。
基于這個(gè)背景,RN 團(tuán)隊(duì)提供了 JSI (JavaScript Interface)框架,JSI 并不是 RN 的一部分,JSI 可以視作一個(gè)兼容層,意在磨平不同 JS 引擎中的差異性。
JSI 實(shí)現(xiàn)了引擎切換,比如在 iOS 平臺(tái)運(yùn)行的 JSCore ,在 Andriod 中運(yùn)行的是 v8 引擎。
JSI 同樣提供了抽象的 API 接口,定義了與各個(gè) JS 引擎交互的接口。
在 JS 中調(diào)用 C++ 注入到 JS 引擎中的方法,數(shù)據(jù)載體格式是通過 HostObject 接口規(guī)范化后的,摒棄了舊架構(gòu)中以 JSON 作為數(shù)據(jù)載體的異步機(jī)制,讓 JS 和 C++ 相互感知。
明白了 RN 內(nèi)部運(yùn)轉(zhuǎn)的背景之后,我們開始正式進(jìn)入 RN 的世界。
四 走進(jìn) React Native 的世界
React Native 將原生開發(fā)的最佳部分與 React 相結(jié)合, 致力于成為構(gòu)建用戶界面的頂尖 JavaScript 框架。
React Native 開發(fā)和傳統(tǒng)的 web 端 React 應(yīng)用開發(fā)類似,并且都是 js 語言,使得 web 開發(fā)者上手 RN 開發(fā)特別簡(jiǎn)單。
在 React web 應(yīng)用中,打包,部署到上線的產(chǎn)物,是一個(gè) html ,css,js 文件的集合體,最后把這些產(chǎn)物放在服務(wù)器上就可以了。
但是在 RN 中,最后打包產(chǎn)物是一個(gè) js 文件,叫做 jsbundle ,在 Native 端運(yùn)行 RN 項(xiàng)目,本質(zhì)上是遠(yuǎn)程拉取了 jsbundle ,并通過上述的 js 引擎運(yùn)行當(dāng)前 jsbundle,每次運(yùn)行一個(gè) bundle 就需要外層容器提供一個(gè) js 引擎。
在 React 構(gòu)建的應(yīng)用為單頁面應(yīng)用,如果存在多個(gè)頁面,可以通過路由的方式實(shí)現(xiàn)頁面的跳轉(zhuǎn),在 RN 中,也有一些解決方案,通常的手段是一個(gè) jsbundle 對(duì)應(yīng)一個(gè)頁面,或者是一個(gè) jsbundle 對(duì)應(yīng)多個(gè)頁面,如下圖所示:
如果采用,原生 + RN + H5 等融合的技術(shù)方案開發(fā)的話,單 jsbundle 對(duì)應(yīng)單頁面的方式比較適合,但是如果是 Native 作為外層容器,里面都頁面都是 RN 的話,單頁面多 bundle 也是一個(gè)不錯(cuò)的選擇。
基礎(chǔ)用法
知道了 RN 的本質(zhì)之后,我們看一下 RN bundle 的注冊(cè),在 RN 中每一個(gè)應(yīng)用都有一個(gè)入口文件,RN 中提供了注冊(cè)根本應(yīng)用的方法,那就是 AppRegistry,這一點(diǎn)和 React web 應(yīng)用會(huì)有一些區(qū)別,web 應(yīng)用中,主要依賴于 react-dom 中提供的 api ,但是在 RN 項(xiàng)目中,無需再下載 react-dom,取而代之的是 react-native 包。
我們先來試著注冊(cè)一個(gè) RN 應(yīng)用:
import {AppRegistry} from 'react-native' /* 根組件 */ import App from './app' AppRegistry.registerComponent('Root', () => <App />)
如上我們注冊(cè)了 Root ,指向了組件 App。接下來就可以在 App 就可以正常開發(fā)了。
在瀏覽器端,可以用 DOM 標(biāo)簽或者組件,但是在 RN 中是沒有 DOM 的,所以如果想要引入原生的視圖組件,就必須從 react-native 中引入,下面我們就編寫一下 App 組件:
import react from 'react' import { View, Text } from 'react-native'; function App(){ return <View> <Text> Hello,React Native! </Text> </View> }
除了基礎(chǔ)的視圖容器組件之外,RN 還提供了一些移動(dòng)端常用的組件,比如列表組件 ScrollView,SectionList 等。
事件
對(duì)于一些用戶交互事件,RN 中也提供了對(duì)應(yīng)事件組件載體,比如點(diǎn)擊事件用的是 TouchableOpacity。 如下所示
function App(){ /* 處理點(diǎn)擊事件 */ const handlePress = ()=>{} return <TouchableOpacity onPress={handlePress} > <Text> click </Text> </TouchableOpacity> }
樣式
在 RN 中,是沒有 css 樣式文件的,RN 中的樣式就和 CSS IN JS 類似,都是通過 JS 來完成的,RN 提供了 StyleSheet 可以創(chuàng)建 style 對(duì)象,如下所示:
import { StyleSheet, View } from "react-native" const styles = StyleSheet.create({ container: { flex: 1, padding: 24, backgroundColor: "#eaeaea" } }) function App(){ return <View style={styles.container} > 樣式處理 </View> }
對(duì)于 RN 的基礎(chǔ)使用,如果參考官方文檔,學(xué)習(xí)成本不高,上手也很快。
弄明白 RN 的運(yùn)行環(huán)境和基礎(chǔ)使用之后,那么都知道 RN 最終的打包產(chǎn)物只是一個(gè) js 文件,那么這個(gè) js 文件是怎么運(yùn)行到 native 應(yīng)用中的,又是怎么和 native 應(yīng)用進(jìn)行交互的呢?
接下來文章中我們會(huì)對(duì) RN 的原理進(jìn)行探秘,探索一下 RN 內(nèi)部運(yùn)轉(zhuǎn)的機(jī)制。
另一方面,現(xiàn)在的動(dòng)態(tài)化方案已經(jīng)不僅僅是 Android 和 iOS 雙端,而是 Android ,iOS ,web ,小程序四端,我們通過 RN 進(jìn)入到跨端動(dòng)態(tài)化方案上來,研究一下以 React 做 dsl 四端動(dòng)態(tài)化方案的現(xiàn)狀與未來。
五 總結(jié)
本文從跨端發(fā)展現(xiàn)狀,再到 RN 運(yùn)轉(zhuǎn)的本質(zhì) JS 引擎,再到 RN 的使用,講述了移動(dòng)端動(dòng)態(tài)化的一個(gè)落地方案。 如果沒有用過 RN 開發(fā)過 app 應(yīng)用的同學(xué),可以嘗試跑一下基礎(chǔ) demo 。
以上就是React跨端動(dòng)態(tài)化之從JS引擎到RN落地詳解的詳細(xì)內(nèi)容,更多關(guān)于React跨端動(dòng)態(tài)化JS引擎RN的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React?Fiber?樹思想解決業(yè)務(wù)實(shí)際場(chǎng)景詳解
這篇文章主要為大家介紹了React?Fiber?樹思想解決業(yè)務(wù)實(shí)際場(chǎng)景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12react中如何對(duì)自己的組件使用setFieldsValue
react中如何對(duì)自己的組件使用setFieldsValue問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03React利用插件和不用插件實(shí)現(xiàn)雙向綁定的方法詳解
我們知道在 angular 中數(shù)據(jù)時(shí)雙向綁定的;而在 react 中,數(shù)據(jù)是向一個(gè)方向傳遞:從擁有者到子節(jié)點(diǎn)。也就是我們說的單向數(shù)據(jù)綁定。那如何實(shí)現(xiàn)雙向綁定呢?下面這篇文章主要給大家介紹了關(guān)于React利用插件和不用插件實(shí)現(xiàn)雙向綁定的方法,需要的朋友可以參考下。2017-07-07淺析history 和 react-router 的實(shí)現(xiàn)原理
react-router 版本更新非???但是它的底層實(shí)現(xiàn)原理確是萬變不離其中,在本文中會(huì)從前端路由出發(fā)到 react-router 原理總結(jié)與分享,本文對(duì)history 和 react-router實(shí)現(xiàn)原理講解的非常詳細(xì),需要的朋友跟隨小編一起看看吧2023-08-08React+umi+typeScript創(chuàng)建項(xiàng)目的過程
這篇文章主要介紹了React+umi+typeScript創(chuàng)建項(xiàng)目的過程,結(jié)合代碼介紹了項(xiàng)目框架搭建的方式,本文給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02React生命周期與父子組件間通信知識(shí)點(diǎn)詳細(xì)講解
生命周期函數(shù)指在某一時(shí)刻組件會(huì)自動(dòng)調(diào)用并執(zhí)行的函數(shù)。React每個(gè)類組件都包含生命周期方法,以便于在運(yùn)行過程中特定的階段執(zhí)行這些方法2022-11-11