譯注: 這是今年5月份React Native剛發(fā)布的時(shí)候赐写,在code.facebook.com發(fā)布的一篇博客鸟蜡。時(shí)隔5個(gè)月,這篇文章依然值得一讀挺邀,尤其是對(duì)于想了解為何Facebook要開發(fā)并發(fā)布React Native的新手揉忘、對(duì)于React Native的由來以及和其它框架的區(qū)別感興趣的同學(xué),都可以讀一讀這篇文章悠夯。
來源:code.facebook.com 原文鏈接 作者:Tom Occhino
如果你對(duì)React沒有什么了解癌淮,你可以先去React官方網(wǎng)站閱讀相關(guān)的內(nèi)容躺坟。你也可以直接從React Native開始了解沦补,這是我們在2015年F8展會(huì)發(fā)布的新框架。
一切從React開始
我們在兩年前就公開了我們的React框架咪橙,并且它取得了令人矚目的成長夕膀,不論是在Facebook內(nèi)還是外部。今天美侦,即使沒有任何人強(qiáng)迫产舞,F(xiàn)acebook內(nèi)部的很多web項(xiàng)目都已經(jīng)使用React構(gòu)建,它也逐步被工業(yè)界廣泛采用菠剩。工程師們選擇每天使用React來開發(fā)易猫,因?yàn)樗沟霉こ處焸兛梢园迅嗟臅r(shí)間和精力用于關(guān)注他們的產(chǎn)品本身,而不是應(yīng)付框架帶來的各種問題具壮。隨著我們的不斷使用准颓,終于,我們開始了解是什么使React如此強(qiáng)大棺妓。
React強(qiáng)迫我們把我們的應(yīng)用劃分成多個(gè)互不相關(guān)的組件,每個(gè)組件作為一個(gè)獨(dú)立的視圖怜跑。這使得我們更容易迭代我們的產(chǎn)品,因?yàn)槲覀儾挥迷诟膭?dòng)一小部分的時(shí)候把整個(gè)系統(tǒng)都裝在我們腦子里峡眶。最重要的是,React包裝了復(fù)雜而易變的DOM API植锉,改為提供一個(gè)聲明式的結(jié)構(gòu)辫樱,使得整個(gè)程序模型變得抽象而簡單汽煮。我們發(fā)現(xiàn)當(dāng)我們使用React來構(gòu)建網(wǎng)頁時(shí)棚唆,我們的代碼變得十分可預(yù)測。這種可預(yù)測性使得我們在快速的迭代產(chǎn)品時(shí)更多的信任已有的代碼心例,最終我們的應(yīng)用程序也變得更為可靠宵凌。更進(jìn)一步,不僅僅擴(kuò)大我們的應(yīng)用規(guī)模變得更容易了瞎惫,我們的團(tuán)隊(duì)規(guī)模也更容易進(jìn)行調(diào)整译株。
我們一起對(duì)web產(chǎn)品經(jīng)快速迭代后,我們已經(jīng)可以用React去創(chuàng)建一些棒極了的產(chǎn)品乘寒,包括Facebook.com的很多組件匪补。在此基礎(chǔ)上,我們還構(gòu)建了一些Javascript頂層的框架蚤氏,例如Relay踊兜,這使得我們的數(shù)據(jù)獲取流程也變得更為簡單。當(dāng)然于游,web并不是唯一的目標(biāo)典蝌,F(xiàn)acebook也有一些被廣泛使用的Android和iOS應(yīng)用,是基于一些完全不相關(guān)的技術(shù)棧來構(gòu)建的鸠澈。不得不為每個(gè)平臺(tái)去構(gòu)建App使得我們的工程師團(tuán)隊(duì)不得不被分隔成幾個(gè)部分去運(yùn)作截驮,而這還不是移動(dòng)應(yīng)用開發(fā)唯一的難點(diǎn)。
為什么原生開發(fā)如此困難
有很多關(guān)于原生開發(fā)環(huán)境和web開發(fā)比起來難的多的解釋涵妥。舉例來說坡锡,在屏幕上去布局一個(gè)東西就十分困難窒所。我們往往不得不自己去計(jì)算視圖的大小和位置帆锋。我們也沒辦法像網(wǎng)站開發(fā)那樣用React或Relay來簡化我們的開發(fā)流程或者擴(kuò)大我們的工程師團(tuán)隊(duì)锯厢。而且對(duì)我們來說遷移到移動(dòng)平臺(tái)最痛苦的事情,就是它大幅的降低了我們的開發(fā)效率实辑。
在開發(fā)Web應(yīng)用時(shí)剪撬,我們只需要保存我們的文件,然后在瀏覽器中點(diǎn)擊刷新婿奔,就可以看到改變的結(jié)果萍摊。而在原生開發(fā)的過程中如叼,我們每次改動(dòng)都得重新編譯和構(gòu)建,即使我所做的僅僅是把一個(gè)文本框在屏幕上挪動(dòng)了幾個(gè)像素踊沸。這使得我們的工程師在做很多工作的時(shí)候變得更加緩慢社证,尤其是當(dāng)一個(gè)大工程的編譯特別的慢的時(shí)候。為原生開發(fā)還使得我們?yōu)樾鹿δ苓M(jìn)行測試變得十分困難腺律。在Facebook宜肉,我們一個(gè)網(wǎng)站可能每天就要發(fā)布兩次,這樣我們幾乎立刻就能獲得實(shí)驗(yàn)反饋之斯。而在移動(dòng)設(shè)備上遣铝,我們經(jīng)常要等上幾個(gè)星期甚至是幾個(gè)月來等待Alpha/Beta測試的結(jié)果。因?yàn)椤芭艿目臁笔荈acebook的團(tuán)隊(duì)基因瘫絮,然而在移動(dòng)設(shè)備上我們實(shí)在沒法和web上跑的一樣快。那我們?yōu)槭裁匆婚_始要放棄用web呢蝇裤?
我們現(xiàn)在為不同平臺(tái)單獨(dú)開發(fā)原生APP频鉴,最重要的原因是我們能創(chuàng)造最佳的用戶體驗(yàn)垛孔,并且能和這個(gè)平臺(tái)的習(xí)慣保持一致。
為什么原生開發(fā)如此必要
即使開發(fā)原生APP要耗費(fèi)更多的時(shí)間狭莱,但也有很多因素導(dǎo)致我們通過原生應(yīng)用可以給用戶在移動(dòng)平臺(tái)帶來比web更好的用戶體驗(yàn)概作。譬如說腋妙,我們可以使用原生平臺(tái)特有的UI組件讯榕,譬如地圖、日期選擇器愚屁、開關(guān)霎槐,還有導(dǎo)航棧。雖然在web上重新實(shí)現(xiàn)這些組件是可能的袭景,但我們至今為止并沒有在web上取得和原生完全一樣的感受碍岔,并且他們也不會(huì)隨著平臺(tái)的進(jìn)步而自動(dòng)更新。我們也很難在web上構(gòu)建復(fù)雜的手勢識(shí)別系統(tǒng)榆纽,我們甚至還沒有一個(gè)適當(dāng)?shù)墓ぞ呋蛘唛_發(fā)指南來幫助我們構(gòu)建這樣一個(gè)系統(tǒng)。
在web上饥侵,我們也沒有一個(gè)足夠完善的線程模型衣屏,所以我們很難利用多線程并行執(zhí)行工作。我們可以用web的Worker機(jī)制在后臺(tái)執(zhí)行一部分程序邏輯膨疏,但依然無法去做一些高負(fù)荷的數(shù)值計(jì)算,譬如在主線程以外的地方去進(jìn)行圖片解碼佃却、文本布局等等窘俺。這可能是開發(fā)一個(gè)高性能和快速響應(yīng)的web app最大的難點(diǎn)瘤泪。
將兩個(gè)世界合二為一对途?
我們最夢寐以求的事情掀宋,就是既能具備原生應(yīng)用的用戶體驗(yàn)劲妙,又能獲得我們用React開發(fā)web應(yīng)用的開發(fā)體驗(yàn)儒喊。要想達(dá)到這樣的目標(biāo)怀愧,我們有幾條路可以走:
使用WebView
最簡單的辦法就是在原生包裝的應(yīng)用程序中,插入一個(gè)WebView芯义。我們幾年前就開始做這樣的嘗試扛拨,并且我們確實(shí)認(rèn)為這個(gè)方法不錯(cuò)。盡管我們的實(shí)現(xiàn)還達(dá)不到我們想要的規(guī)那筇化和性能,這種方法是最靈活的芽丹,并且能沿用全部web開發(fā)的習(xí)慣卜朗,譬如React的各種好處和web的快速迭代流程。但不幸的是蚊俺,因?yàn)樗械匿秩径加蓋eb相關(guān)的技術(shù)來完成惹悄,我們依然無法得到一個(gè)真正原生的用戶體驗(yàn)。
移植React的原生版本
把React移植到原生也是一個(gè)好主意暂殖。實(shí)際上当纱,我們在iOS平臺(tái)上已經(jīng)這么做了坡氯,這個(gè)項(xiàng)目叫做ComponentKit,這也是我們昨天在F8展會(huì)上開源的項(xiàng)目手形。用ComponentKit悯恍,你可以獲得React所有的好處,尤其是聲明式的瞬欧、可預(yù)測的UI罢防。我們還能獲得原生開發(fā)環(huán)境的各種強(qiáng)大優(yōu)勢咒吐,使用平臺(tái)獨(dú)有的組件和復(fù)雜的手勢處理属划,或者異步的進(jìn)行圖片解碼贬墩、文本布局陶舞、和渲染等等。不僅如此肿孵,因?yàn)镃omponentKit用了flexbox作為布局方案停做,你不再需要自行去管理應(yīng)用中各項(xiàng)視圖的位置,所以你的代碼最終能變得簡潔而易于維護(hù)官份。
不過這個(gè)方案也有幾處不太重要的負(fù)面影響烙丛。首先河咽,它是iOS獨(dú)有的,所以如果我們想在Android上獲得一樣的好處忘蟹,我們只能去創(chuàng)造一個(gè)獨(dú)立的實(shí)現(xiàn)媚值,然后教會(huì)工程師怎么去用它。并且垃你,我們也沒辦法同時(shí)使用我們?yōu)閣eb頂層構(gòu)建的各種工具喂很,譬如幫助我們解決了規(guī)模性的數(shù)據(jù)獲取的許多痛點(diǎn)的Relay少辣。最重要的是羡蛾,我們沒能改善開發(fā)速度中最大的問題——我們還得每次修改之后,重新編譯和構(gòu)建工程忙干。
用腳本封裝原生
如果我們用JavaScript去調(diào)用原生API,我們應(yīng)當(dāng)能獲得原生平臺(tái)的所有強(qiáng)大之處乾翔,同時(shí)還能享受快速迭代和使用我們現(xiàn)有JavaScript上基礎(chǔ)設(shè)施的好處施戴。不僅如此赞哗,因?yàn)榛贘avaScript構(gòu)建,我們應(yīng)當(dāng)能使得這樣技術(shù)椩屡跨平臺(tái)藤乙。這聽起來恰好是我們要的全部湾盒,而且毫不意外有成千上萬的框架正在這么干罚勾,然而實(shí)際上問題并沒有被直截了當(dāng)?shù)慕鉀Q尖殃。
用腳本封裝原生是一件需要技巧的事情
如果我們只是同步的在原生環(huán)境和解釋環(huán)境之間調(diào)用缔俄,我們的UI線程很可能會(huì)被JavaScript執(zhí)行阻塞住俐载。要提升界面的響應(yīng)效率遏佣,我們知道我們必須把JavaScript放到主線程之外執(zhí)行状婶,但這么做其實(shí)很困難草姻。最直接的困難就是資源訪問競爭撩独。如果我們的JavaScript訪問什么正好在被別的線程用的東西(譬如一個(gè)渲染的View的尺寸)跌榔,系統(tǒng)就只能加鎖來確保方案安全,而這又會(huì)導(dǎo)致UI線程的卡頓担平。還有一個(gè)問題在于每次原生和JavaScript虛擬機(jī)之間互相訪問暂论,在訪問過程中都會(huì)帶來極大的開銷。如果我們要經(jīng)澄胖跨線程訪問,我們不得不一次又一次的經(jīng)歷這種開銷薪棒。
所以如果我們不找到一個(gè)正確的辦法俐芯,我們的應(yīng)用可能比我們整個(gè)用原生寫或者整個(gè)用JavaScript寫還要糟糕的多。我們不能只是把用戶接口API又同步的封裝了一遍然后就期待能獲得一個(gè)流暢的亏拉、和原生APP一樣的體驗(yàn)及塘。我們必須要改變一些基礎(chǔ)層次的設(shè)計(jì)來確保我們的系統(tǒng)傳遞消息永遠(yuǎn)是異步的,這樣我們就可以把這些消息以一定的單位來打包發(fā)送芳肌,來盡可能減少一些跨線程交互的開銷肋层。
幸運(yùn)的是栋猖,React恰好給了我們一個(gè)適當(dāng)?shù)哪P蛠磉_(dá)到這個(gè)結(jié)果
引入React Native
因?yàn)镽eact組件本來就被設(shè)計(jì)為一個(gè)純粹的、無副作用的函數(shù)肃拜,函數(shù)返回每一個(gè)時(shí)刻當(dāng)時(shí)的View狀態(tài)燃领,這樣我們無需讀取底層View的狀態(tài)就可以為它寫入新的狀態(tài)锦援。在瀏覽器環(huán)境里灵寺,React使用一個(gè)非阻塞的方式來維護(hù)DOM,但React最棒的地方在于它其實(shí)可以構(gòu)成一個(gè)抽象的概念凉泄,而不是死死的綁定在DOM上蚯根。React可以綁定到任何必要的視圖系統(tǒng)上颅拦,譬如iOS的UIKit等等。
這意味著我們只要很少的工作就可以用Github上已有的React來構(gòu)建真正原生的移動(dòng)應(yīng)用右锨。移動(dòng)環(huán)境唯一的區(qū)別在于不同瀏覽器里的React用div和span標(biāo)簽來渲染绍移,我們用一個(gè)植入的JavasScriptCore來運(yùn)行JavaScript,然后渲染平臺(tái)獨(dú)有的組件轧抗。
這個(gè)方案帶來的一個(gè)巨大好處在于我們可以逐步的進(jìn)行方案替換瞬测。我們既可以在新項(xiàng)目中直接基于React構(gòu)建月趟,也可以在舊項(xiàng)目的合適部分中去嘗試性的使用它。正如我們剛開始在Facebook.com中使用React也僅僅是在某些地方穷躁,我們也沒必要為了React的好處而把所有Facebook的所有應(yīng)用重寫一遍折砸。
這個(gè)方案真的可行
我們現(xiàn)在已經(jīng)在Facebook的產(chǎn)品線上使用了React Native沙峻。盡管還有一堆工作需要進(jìn)行摔寨,它真的讓我們感覺不錯(cuò)。需要注意的是我們不再強(qiáng)調(diào)所謂的“一次編寫删顶,隨處運(yùn)行”逗余。不同的平臺(tái)應(yīng)該有不同的外觀季惩、感覺画拾、功能等等。我們?nèi)匀恍枰獮椴煌钠脚_(tái)去做一些額外的工作旗闽。但是我們只需要同一幫工程師就可以覆蓋到不同的平臺(tái),也不需要去學(xué)習(xí)各個(gè)平臺(tái)自己的技能樹嫡意。我們把這個(gè)方案叫做“一次學(xué)習(xí)鹅很,隨處編寫”罪帖。
![Sample1](http://7xij0o.com2.z0.glb.qiniucdn.com/atta/post/41/3.jpg)
如果你有一個(gè)iPhone設(shè)備整袁,你已經(jīng)可以從App Store中下載到我們用React Native構(gòu)建的一些APP佑吝。Facebook Groups是一個(gè)混合開發(fā)的應(yīng)用芋忿,一部分由原生代碼構(gòu)建,一部分由React Native的JavaScript代碼構(gòu)建痹仙。而Facebook Ads Manager則是一個(gè)徹底用React Native構(gòu)建的應(yīng)用殉了。
開源
在Facebook薪铜,我們的使命之一就是讓世界變得更加開放和連接隔箍。所以我們也希望通過開源來為這個(gè)使命貢獻(xiàn)。React Native并不例外滨达。我們意識(shí)到工程師組織的難題并不是Facebook獨(dú)有的問題弦悉,而且我們也希望盡可能的公開開發(fā)蟆炊,與面臨相似挑戰(zhàn)的人進(jìn)行合作涩搓。
今天污秆,我們高興的宣布React Native的iOS版本已經(jīng)在Github公開劈猪。安卓支持也即將到來。我們也在持續(xù)努力推進(jìn)React的web版本良拼,但我們希望盡早發(fā)布這個(gè)初始的iOS版本战得,這樣我們就可以從其它對(duì)此方案感興趣的人那里獲得反饋。記住現(xiàn)在在React Native中還有很多的問題或者尚未實(shí)現(xiàn)的部分庸推,我們非常歡迎您的反饋建議常侦,我們也非常期待看到您用React Native所構(gòu)建出的App!