React Native: Learn once坷剧,Write anywhere!
Java: Write once, Run anywhere!
跨平臺(tái)的方案發(fā)展歷史
-
web容器時(shí)代: 基于web等相關(guān)技術(shù)通過瀏覽器實(shí)現(xiàn)界面與功能惰爬。典型的框架有Cordova 、ionic惫企、微信小程序 瀏覽器加載H5頁面的過程如下:
初始化 webview -> 請(qǐng)求頁面 -> 下載數(shù)據(jù) -> 解析HTML -> 請(qǐng)求 js/css 資源 -> dom 渲染 -> 解析 JS 執(zhí)行 -> JS 請(qǐng)求數(shù)據(jù) -> 解析渲染 -> 下載渲染圖片
如圖: 在此過程中會(huì)經(jīng)歷一系列性能以及用戶體驗(yàn)的問題
涉及到系統(tǒng)的能力(拍照,定位等)還需要做相應(yīng)的JSBridge,這在提升開發(fā)效率的同時(shí)也損失了一些性能和用戶體驗(yàn)补鼻。
-
泛web容器化時(shí)代: 采用web標(biāo)準(zhǔn)進(jìn)行開發(fā),核心在于頁面的渲染繪制在運(yùn)行時(shí)交給了原生系統(tǒng)。典型框架有React Native雅任、Weex 以及快應(yīng)用
在業(yè)務(wù)實(shí)現(xiàn)中,我們只用到了web標(biāo)準(zhǔn)中小部分內(nèi)容咨跌,為了達(dá)到開發(fā)效率與性能穩(wěn)定的平衡沪么,就放棄了瀏覽器的控件渲染能力,而是采用原生組件的渲染锌半。
-
自繪引擎時(shí)代:
做過React Native 或者 Weex 開發(fā)的小伙伴都知道禽车,有時(shí)候我們?yōu)榱藢?shí)現(xiàn)一個(gè)控件,iOS 和Android 兩個(gè)平臺(tái)的代碼都要進(jìn)行適配,React Native沒有提供統(tǒng)一的API; 甚至API發(fā)生變化刊殉,又得升級(jí)改造殉摔,尤其RN在開始的時(shí)候版本的迭代速度是很快的,這個(gè)改造過程非常痛苦,會(huì)遇到各種奇奇怪怪的bug。這個(gè)時(shí)候Flutter的出現(xiàn)记焊,讓很多人看到了一絲絲希望逸月。
Flutter 從頭到尾重寫了一套跨平臺(tái)的UI框架, 在頁面布局方面做到了一套代碼多個(gè)平臺(tái)運(yùn)行, 并且支持JIT 和 AOT
Flutter 是移動(dòng)UI框架只是接管了渲染層**
Flutter 介紹
Flutter 是基于Google的物聯(lián)網(wǎng)操作系統(tǒng)FuchsiaOS(這是Google 除了ChromeOS,Android外的第三個(gè)操作系統(tǒng) )的UI框架, 基于Zircon內(nèi)核,而不是Android 用的linux內(nèi)核,他對(duì)硬件的要求較低遍膜。
Flutter 的架構(gòu)設(shè)計(jì)
Embedder 是操作系統(tǒng)適配層碗硬,實(shí)現(xiàn)了渲染 Surface 設(shè)置瓤湘,線程設(shè)置,以及平臺(tái)插件等平臺(tái)相關(guān)特性的適配恩尾。從這里我們可以看到弛说,F(xiàn)lutter 平臺(tái)相關(guān)特性并不多,這就使得從框架層面保持跨端一致性的成本相對(duì)較低翰意。
Engine 層主要包含 Skia木人、Dart 和 Text,實(shí)現(xiàn)了 Flutter 的渲染引擎冀偶、文字排版醒第、事件處理和 Dart 運(yùn)行時(shí)等功能。Skia 和 Text 為上層接口提供了調(diào)用底層渲染和排版的能力蔫磨,Dart 則為 Flutter 提供了運(yùn)行時(shí)調(diào)用 Dart 和渲染引擎的能力淘讥。而 Engine 層的作用,則是將它們組合起來堤如,從它們生成的數(shù)據(jù)中實(shí)現(xiàn)視圖渲染蒲列。
Framework 層則是一個(gè)用 Dart 實(shí)現(xiàn)的 UI SDK,包含了動(dòng)畫搀罢、圖形繪制和手勢(shì)識(shí)別等功能蝗岖。為了在繪制控件等固定樣式的圖形時(shí)提供更直觀、更方便的接口榔至,F(xiàn)lutter 還基于這些基礎(chǔ)能力抵赢,根據(jù) Material 和 Cupertino 兩種視覺設(shè)計(jì)風(fēng)格封裝了一套 UI 組件庫。我們?cè)陂_發(fā) Flutter 的時(shí)候唧取,可以直接使用這些組件庫铅鲤。
Hot Reload
Flutter
支持亞秒級(jí)熱重載,Android Studio
和VSCode
都支持Hot Reload
的特性枫弟。但需要區(qū)分的是邢享,熱重載和熱更新是不同的兩個(gè)概念,熱重載是在運(yùn)行調(diào)試狀態(tài)下淡诗,將新代碼直接更新到執(zhí)行中的二進(jìn)制骇塘。而熱更新是在上線后,通過Runtime
或其他方式韩容,改變現(xiàn)有執(zhí)行邏輯AOT && JIT
JIT: Just in Time 即時(shí)編譯 邊解釋邊執(zhí)行款违,開發(fā)測試效率高,但運(yùn)行速度和執(zhí)行性能則會(huì)因?yàn)檫\(yùn)行時(shí)即時(shí)編譯受到影響 一個(gè)程序在它運(yùn)行的時(shí)候創(chuàng)建并且運(yùn)行了全新的代碼群凶,而并非那些最初作為這個(gè)程序的一部分保存在硬盤上的固有的代碼插爹。
AOT: Ahead of Time 運(yùn)行前編譯 可以生成被直接執(zhí)行的二進(jìn)制代碼,運(yùn)行速度快请梢、執(zhí)行性能表現(xiàn)好递惋,但每次執(zhí)行前都需要提前編譯柔滔,開發(fā)測試效率低。
在android里面萍虽,JIT會(huì)把程序?qū)崟r(shí)編譯為機(jī)器字節(jié)碼睛廊,然后虛擬機(jī)讀取,打開程序~而AOT是在安裝的時(shí)候預(yù)先打包好了字節(jié)碼放在手機(jī)內(nèi)部儲(chǔ)存里面杉编,打開程序直接讀取預(yù)先打包好的玩意就可以了
Flutter
支持AOT
(Ahead of time
)和JIT
(Just in time
)兩種編譯模式超全,JIT
模式支持在運(yùn)行過程中進(jìn)行Hot Reload
。刷新過程是一個(gè)增量的過程邓馒,由系統(tǒng)對(duì)本次和上次的代碼做一次snapshot
嘶朱,將新的代碼注入到DartVM
中進(jìn)行刷新。但有時(shí)會(huì)不能進(jìn)行Hot Reload
光酣,此時(shí)進(jìn)行一次全量的Hot Reload
即可疏遏。而
AOT
模式則是在運(yùn)行前預(yù)先編譯好,這樣在每次運(yùn)行過程中就不需要進(jìn)行分析救军、編譯财异,此模式的運(yùn)行速度是最快的。Flutter
同時(shí)采用了兩種方案唱遭,在開發(fā)階段采用JIT
模式進(jìn)行開發(fā)戳寸,在release
階段采用AOT
模式,將代碼打包為二進(jìn)制進(jìn)行發(fā)布拷泽。在開發(fā)原生應(yīng)用時(shí)疫鹊,每次修改代碼后都需要重新編譯,并且運(yùn)行到硬件設(shè)備上司致。由于
Flutter
支持Hot Reload
拆吆,可以進(jìn)行熱重載,對(duì)項(xiàng)目的開發(fā)效率有很大的提升脂矫。由于
Flutter
實(shí)現(xiàn)機(jī)制支持JIT
的原因锈拨,理論上來說是支持熱更新以及服務(wù)器下發(fā)代碼的「耄可以從服務(wù)器。但是由于這樣會(huì)使性能變差娄昆,而且還有審核的問題佩微,所以Flutter
并沒有采用這種方案。Flutter使用的開發(fā)語言---Dart
Dart 是谷歌開發(fā)的一種通用編程語言,亮相于2011年的GOTO大會(huì)上 它被用于構(gòu)建 Web萌焰、服務(wù)器哺眯、桌面和移動(dòng)應(yīng)用程序
Dart是面向?qū)ο蟮摹㈩惗x的扒俯、單繼承的語言奶卓。它的語法類似C語言一疯,可以轉(zhuǎn)譯為JavaScript,支持接口(
interfaces)
夺姑、混入(mixins)
墩邀、抽象類(abstract classes)
、具體化泛型(reified generics)
盏浙、可選類型(optional typing)
和sound type system
眉睹。最初設(shè)計(jì)Dart,是Google的一幫程序員出于對(duì)JavaScript的不滿废膘,決定自己搞一個(gè)新語言用來替換JavaScript的竹海,所以剛開始Dart也就是用來作為瀏覽器腳本運(yùn)行在瀏覽器中的。為了推廣Dart丐黄,Google在Chrome中內(nèi)置了DartVM的引擎斋配。有了運(yùn)行環(huán)境,加上用戶群的可觀數(shù)量灌闺,Dart最初也贏得了部分前端開發(fā)者的青睞艰争。但是隨著NodeJS 的火熱,JavaScript煥發(fā)了第二春,可以說是在編程界無孔不入菩鲜,幾乎成就了JS程序員口中的“凡是能被JS實(shí)現(xiàn)的园细,最終都要被JS實(shí)現(xiàn)”的愿景,前端的開發(fā)模式因此而改變接校。再加上React猛频、React-Native、Vue等框架的崛起蛛勉,一句話總結(jié)就是JavaScript很忙鹿寻。
Dart 逐漸被開發(fā)者遺忘了,2015年 Google將內(nèi)置的Dart 引擎從Chrome中移除,但是Google 內(nèi)部孵化了一個(gè)跨平臺(tái)項(xiàng)目—Flutter ,同時(shí)Dart在服務(wù)端和瀏覽器前端也在不遺余力的發(fā)展(服務(wù)端可以編寫命令行程序,前端可以編譯成Javascript運(yùn)行在瀏覽器中), Google將Dart 作為了操作系統(tǒng)Fuchsia的官方開發(fā)語言
Dart 的特性
- 單線程異步事件模型
- 強(qiáng)類型推斷
- 獨(dú)特的
isolate
來實(shí)現(xiàn)多線程 - 面向?qū)ο?/li>
- 全平臺(tái)通吃
- …..
Javascript 和 Dart 的對(duì)比
Dart默認(rèn)是單線程任務(wù)處理诽凌,如果不開啟新的線程毡熏,任務(wù)默認(rèn)在主線程中處理; Javascript也是單線程,但是瀏覽器是多進(jìn)程.
同樣是單線程侣诵,怎么實(shí)現(xiàn)并發(fā)?
作為瀏覽器腳本語言痢法,JavaScript的主要用途是與用戶互動(dòng),以及操作DOM,這決定了它只能是單線程杜顺,否則會(huì)帶來很復(fù)雜的同步問題财搁。比如,假定JavaScript同時(shí)有兩個(gè)線程躬络,一個(gè)線程在某個(gè)DOM節(jié)點(diǎn)上添加內(nèi)容尖奔,另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器應(yīng)該以哪個(gè)線程為準(zhǔn)?所以為了避免復(fù)雜性提茁,從一誕生淹禾,JavaScript就是單線程,這已經(jīng)成了這門語言的核心特征. 另外為了利用多核CPU的計(jì)算能力茴扁,HTML5提出Web Worker標(biāo)準(zhǔn)铃岔,允許JavaScript腳本創(chuàng)建多個(gè)線程,但是子線程完全受主線程控制丹弱,且不得操作DOM德撬。所以,這個(gè)新標(biāo)準(zhǔn)并沒有改變JavaScript單線程的本質(zhì)躲胳。
Javascript 是單線程蜓洪,但是不代表他就是在一個(gè)單線程中完成 html 解析、 構(gòu)建Dom樹和Render樹 坯苹、布局隆檀、 繪制等等一系列的操作花椭。這些操作是由瀏覽器內(nèi)核在多個(gè)線程的協(xié)同寫完成的,比如: GUI 渲染線程劫映、JS引擎線程、事件觸發(fā)線程判帮、定時(shí)器線程为鳄、異步請(qǐng)求線程...
JS引擎執(zhí)行異步代碼而不用等待裳仆,是因有為有 消息隊(duì)列和事件循環(huán). 消息就是注冊(cè)異步任務(wù)時(shí)添加的回調(diào)函數(shù)
主線程在執(zhí)行完當(dāng)前循環(huán)中的所有代碼后,就會(huì)到消息隊(duì)列取出這條消息(也就是message函數(shù))孤钦,并執(zhí)行它歧斟。到此為止,就完成了工作線程對(duì)主線程的通知偏形,回調(diào)函數(shù)也就得到了執(zhí)行静袖。如果一開始主線程就沒有提供回調(diào)函數(shù),AJAX線程在收到HTTP響應(yīng)后俊扭,也就沒必要通知主線程队橙,從而也沒必要往消息隊(duì)列放消息
Dart 是怎樣實(shí)現(xiàn)并發(fā)的呢?在Flutter 中引入了isolate
的概念萨惑,isolate
(隔離區(qū))與常規(guī)的線程有較大的區(qū)別(線程之間不共享內(nèi)存)可以視為一個(gè)Worker,每一個(gè)Worker中維護(hù)著MicroTask 和 Event 隊(duì)列捐康,執(zhí)行邏輯如下圖:
更多細(xì)節(jié)我們后續(xù)有專門的章節(jié)為大家講解。
Dart 與 Javascript的優(yōu)勢(shì)在哪里庸蔼?
Javascript 優(yōu)勢(shì)在于 標(biāo)準(zhǔn)統(tǒng)一, 應(yīng)用范圍廣解总,正如Atwood 定律描述: 凡是能用Javascript寫出來的系統(tǒng),最終都會(huì)用Javascript寫出來朱嘴。目前由于Node.js 、Vue、React萍嬉、Angular等框架的出現(xiàn)乌昔,讓Javascript成了前后端通吃的全棧開發(fā)語言。 Javascript 借鑒了其他語言的特性: 函數(shù)是一等公民 壤追、 原型鏈等...
Dart 是Google Fuchsia系統(tǒng)的官方開發(fā)語言磕道,能夠解決Javascript本身存在的缺陷
Google 為何不直接采用Javascript作為跨平臺(tái)開發(fā)語言而是采用Dart?
- Dart* 支持 AOT 和 JIT ,支持熱重載, 在開發(fā)過程中可以動(dòng)態(tài)下發(fā)代碼,升開發(fā)效率; 而 JavaScript 支持 JIT
- Dart 有Google 爸爸的強(qiáng)力支持
- Javascript 存在性能以及與Native系統(tǒng)的通信需要做很多Bridge 的問題
- Javascript 標(biāo)準(zhǔn)的確認(rèn)需要提交評(píng)審委員會(huì)審理行冰,周期長太長溺蕉,google還是希望能夠盡快完成生態(tài)的布局
Flutter 會(huì)支持熱更新
Flutter高性能的其中一個(gè)重要因素就是因?yàn)镈art在發(fā)布期是AOT,目前階段支持的可能性比較小, 另外蘋果也不允許除了JSCore之外的其他動(dòng)態(tài)編譯/解釋執(zhí)行環(huán)境悼做。
Flutter 為何不支持直接操作攝像機(jī)疯特、GPS等硬件?
按照我們的理解做一個(gè)APP大部分業(yè)務(wù)功能都是頁面的布局渲染肛走,很少牽涉到調(diào)用攝像機(jī)等底層的硬件設(shè)備漓雅。如果Flutter 作為一個(gè)UI渲染引擎,也要做這個(gè)的話其實(shí)就是做了一個(gè)操作系統(tǒng)了朽色。
什么時(shí)候用Native 開發(fā)邻吞?什么時(shí)候用Flutter開發(fā) ?
原生適用于需要頻繁與操作系統(tǒng)底層能力進(jìn)行交互, 大部分純渲染交互的場景用Flutter就可以了
當(dāng)前跨平臺(tái)方案的對(duì)比
Tips
怎樣判斷一門語言是否是AOT還是JIT? 通常來說,看代碼在執(zhí)行前是否需要編譯即可葫男。如果需要編譯抱冷,通常屬于 AOT;如果不需要梢褐,則屬于 JIT. AOT 的典型代表是 C/C++旺遮,它們必須在執(zhí)行前編譯成機(jī)器碼; 而JIT 的代表則包含了如 lua、Javascript 利职、Python 等幾乎所有的腳本語言
-
怎樣判斷一個(gè)技術(shù)能否成為大前端的主流趣效? 判斷一個(gè)技術(shù)是否能成為未來大前端主流技術(shù)發(fā)展的趨勢(shì),主要參考以下幾方面:
- 是否能減少對(duì)底層宿主環(huán)境的依賴
- 能否隔離各終端系統(tǒng)差異
- 能否從原理和運(yùn)行機(jī)制及生態(tài)等方面優(yōu)于現(xiàn)有技術(shù)猪贪,或者為現(xiàn)有技術(shù)瓶頸提供新的解決方案
- 能夠?yàn)殚_發(fā)者提供統(tǒng)一且標(biāo)準(zhǔn)化的能力
跨平臺(tái)方案的選擇要注意的方面
不能僅僅依賴編程語言跷敬、性能、技術(shù)架構(gòu)等因素,要從開發(fā)效率热押、社區(qū)活躍度社區(qū)支持西傀、構(gòu)建發(fā)布、CI等工程化方面考慮
大前端的永恒主題: 效率桶癣、質(zhì)量拥褂、性能 用盡量完整的技術(shù)棧和工具鏈去隔離各終端系統(tǒng)差異,向開發(fā)者提供統(tǒng)一而標(biāo)準(zhǔn)化的能力牙寞。結(jié)合這三大主題看看新技術(shù)是否能夠推動(dòng)去解決業(yè)務(wù)現(xiàn)階段的實(shí)際問題饺鹃,以及具體的落地場景莫秆。如果只是把”完成“落地作為目標(biāo),而忽略了我們具體要通過它去解決什么問題悔详,可能是本末倒置了镊屎,所以我們要有升維思考 降維打擊的思考力。
到此我們已經(jīng)了解了Flutter 相關(guān)的背景知識(shí)茄螃,留給大家一個(gè)問題:Flutter是如何渲染的缝驳?
參考鏈接:
Flutter's Rendering Pipeline
深入理解跨平臺(tái)方案的歷史發(fā)展邏輯
React Native、Flutter等跨平臺(tái)方案怎么選归苍?
Android中的AOT用狱、JIT
Code Push / Hot Update / out of band updates
javac 編譯與JIT編譯
Flutter熱更新與熱加載