做者:Chen Feldmanhtml
發佈日期:2019.07.30前端
原文連接:medium.com/swlh/react-…react
翻譯中有部分是意譯。ios
最近幾年,React Native已經成爲最流行的移動端App開發框架之一。解決了不少開發者常常思考的問題:應該使用原生開發客戶端app,仍是使用web開發Hybird app。git
使用RN開發須要web方面的知識和React經驗,由於它基本是基於React框架的。須要比直接使用Cordova這樣庫更難一些,可是比寫Swift和Kotlin 這兩個原生客戶端的代碼要輕鬆不少。RN能夠經過寫純js代碼得到和原生相似的性能體驗。github
在開始以前,咱們先介紹一下,相比於其餘方案,React Native的定位是什麼。web
在上圖中,選取了一些常見的App開發方式。從左到右,能夠分紅3個陣營:objective-c
原生Native。這意味着你想去使用原生語言開發App,好比ios的Swift或Android的Kotlin。確定會得到最好的性能,而且能夠充分利用設備硬件和原生API。可是,這須要學習兩種不一樣的編程語言,維護兩套代碼,而且可能有雙倍的bug,甚至須要有兩個不一樣的開發團隊。編程
Hybrid。若是你是web開發者或者擁有一個已經熟悉JS、HTML、CSS和某些前端庫的Web團隊,你能夠選擇這種方案,並使用Cordova/Ionic 經過一些步驟使你的網頁變成移動App。這樣咱們只須要學習一個技術棧,可是,在性能,硬件和API的使用上會有限制。react-native
類原生(其實也算是一種Hybrid)。React Native就屬於這類,理論上開發者只須要懂得Web開發知識就能夠了。可是學習曲線會比Hybrid要高一些。開發者須要學習怎麼使用React Native的庫。在某些場景下,可能還須要使用XCode或Android Studio打開項目。可是寫的代碼能夠適用於iOS和Android兩個平臺,開發上的限制也會比Hybrid要小一些。性能表現會更像原生開發,並且能夠更容易地使用一些原生的API。
如今咱們理解了RN的定位,讓咱們對比一下RN和Hybrid的渲染狀況:
從上圖能夠看出,使用Cordova的App是放在webView裏的。這更像是一個在App裏的瀏覽器。用web的概念說,這更像一個web app裏的iFrame。
左邊展現了React Native是怎麼組成的,在RN中的每一個組件,好比:Text、Button、Image等都有一個相對應的原生組件。因此和不少新接觸RN開發者想的不同,RN並無編譯成原生代碼,它作了個JS組件和原生組件的映射。
當咱們這樣在Render函數裏寫了個RN組件:
背後部分預先寫好的原生組件會是這樣的:
若是咱們用iOS來舉例,這些是RN裏面的原生組件代碼:
總的來講,RN團隊已經爲咱們建立和映射了全部的原生組件。咱們須要去作的只是去基於RN組件和庫寫JavaScript代碼。其餘的部分對通常開發者來講都是不可見的,像黑魔法同樣。
因此,看上去咱們只用寫js代碼就能夠了。讓咱們一步步來解釋一下這個架構是怎樣的。從Bridge開始是最合適的:
RN能夠分紅JS 和 Native兩部分,這兩部分都有本身的線程
線程通訊是經過Bridge通訊,傳輸的是JSON信息,其中包含了module id,method id和一些須要的數據。這兩邊並不能直接地相互感知,也不能共享相同的內存。
這有點像不一樣服務器之間通訊,若是你有用不一樣語言寫的後臺服務,你將怎麼在他們之間通訊呢?
不少人認爲隊列是一個很好的解決方案。你發送JSON/XML隊列消息,這個消息聽從相應的協議,而且每一個服務都知道怎麼去讀取和解析成對應的數據和行爲。這個隊列就很像RN裏面的Bridge。
這裏有個例子展現通訊是怎樣進行的,信息被髮送到Bridge。從建立新的View和樣式並在屏幕上顯示,到在移動端設置子組件和進行一些操做:
若是想要在console裏看到Bridge的消息,只須要把下面這個代碼片斷放到index. < platform > .js裏就能夠了
如今咱們知道了RN是怎麼通訊的,而且開始揭曉其中的「黑魔法」。
這也是爲何Android App須要更多的時間去加載,由於須要加載JSCore到項目裏。不過在0.60.2以後,RN可使用Hermes,這對於RN來講是更理想的JS引擎。
在這部分,咱們將經過解析從點擊App圖標到App打開這個流程和其中的一些相關細節。
爲了理解RN是怎麼在背後建立View的,咱們先須要解釋一些基礎概念:
理解了上面的一些基礎概念,讓咱們來看下打開App時,每一步發生了什麼:
用戶點擊App的圖標
UIManager線程:加載全部的Native庫和Native組件好比 Text、Button、Image等
告訴Js線程,Native部分準備好了,Js側開始加載main.bundle.js,這裏麪包含了全部的js和react邏輯以及組件。
Js側經過Bridge發送一條JSON消息到Native側,告訴Native怎麼建立UI。值得一提的是:全部通過Bridge的通訊都是異步的,而且是打包發送的。這是爲了不阻塞UI,舉個栗子:
Shadow線程最早拿到消息,而後建立UI樹
而後,它使用Yoga佈局引擎去獲取全部基於flex樣式的佈局,而且轉化成Native的佈局,寬、高、間距等。。
以後UIManager執行一些操做而且像這樣在屏幕上展現UI:
這些就是啓動App是的主要步驟。
RN基於這個架構有如下優勢:
可是,有優勢確定也會有缺點。下面咱們介紹一下可以解決現有缺點的新架構:Fabric。
咱們已經討論了RN的當前架構,是時候說一下其中的缺陷。能夠看一下Facebook的React團隊負責人在她博客裏提到的。
當前架構的缺點是:
不過不要誤會,Facebook本身也正在使用React Native開發各類app,服務百萬級的日活用戶。同時也有其餘有名的公司在生產環境中使用基於當前架構的RN,好比Wix、Bloomberg、Tesla、Zynga等等。
RN開發團隊正着手去解決上面提到的缺點。
這是以前的RN架構:
這是新的架構圖:
讓咱們來解釋一下這些新的概念:JSI,Fabric,Turbo Modules,和 CodeGen。
JSI(將會替換Bridge) -- 爲了讓JS和Native可以互相感知。將再也不須要經過Bridge傳輸序列化JSON。將容許Native對象被導出成Js對象,反過來也能夠。兩側也會導出能夠被同步調用的API。實際上,架構的其餘部分都是基於這個之上的(Fabric,Turbo Modules等,這些下面會解釋)
Fabric -- UIManager的新名稱,將負責Native端渲染。和當前的Bridge不一樣的是,它能夠經過JSI導出本身的Native函數,在JS層能夠直接使用這些函數引用,反過來,Native層也能夠直接調用JS層。這帶來更好更高效的性能和數據傳輸。
Turbo Modules。記得上面的Native組件嗎?Text、Image、View,他們的新名字叫Turbo Modules。組件的做用是相同的,可是實現和行爲會不一樣。第一,他們是懶加載的(只有當App須要的時候加載),而如今是在啓動時所有加載。另外,他們也是經過JSI導出的,因此JS能夠拿到這些組件的引用,而且在React Natvie JS裏使用他們。尤爲會在啓動的時候帶來更好的性能表現。
CodeGen -- 爲了讓JS側成爲兩端通訊時的惟一可信來源。它可讓開發者建立JS的靜態類,以便Native端(Fabric和Turbo Modules)能夠識別它們,而且避免每次都校驗數據 => 將會帶來更好的性能,而且減小傳輸數據出錯的可能性。
Lean Core -- 是對React Native庫架構的變化。目的是減輕lib的負擔,並幫助社區更快地解決更多pull request。Facebook正在把庫的某些部分拆分出來,經過關注Github就能夠看出他們在這方面的行動了。好比這個:
順便一提,這裏有個例子,你能夠在Chrome裏嘗試一下,這也是JSI如何工做和導出對象的靈感來源:
在Chrome裏打開開發者界面,而後輸入console.log,回車。你將看到native code。這說明console.log實際上是一個Native的函數。
接下來咱們再對比一下使用新架構,App啓動的流程是怎麼樣的。
用戶點擊App的圖標
Fabric加載Native側(沒有Native組件)
而後通知JS線程Native側準備好了,JS側會加載全部的main.bundle.js,裏面包含了全部的js和react邏輯+組件
JS經過一個Native函數的引用(JSI API導出的)調用到Fabric,同時Shadow Node建立一個和之前同樣的UI樹。
Yogo執行佈局計算,把基於Flexbox的佈局轉化成終端的佈局。
Fabric執行操做而且顯示UI==>
爲了完成整個流程,咱們幾乎作了一樣的事情,可是沒有了Bridge,如今咱們能夠有更好的性能,咱們能夠用同步的方式進行操做,甚至能夠對UI上的同步操做進行優先級排序。啓動時間也將更快,App也將更小。
因此,咱們何時能夠上手使用這些東西?
能夠在Github上關注它們各自的更新狀況:
按理說,大多數的更改將逐步完成,並有但願在2019第四季度或2020第一季度發佈。
部分參考文檔,便於更深入地理解: