【React Native】把現代web科技帶給移動開發者(一)

譯註: 這是今年5月份React Native剛發佈的時候,在code.facebook.com發佈的一篇博客。時隔5個月,這篇文章依然值得一讀,尤其是對於想了解爲何Facebook要開發併發布React Native的新手、對於React Native的由來以及和其它框架的區別感興趣的同學,都可以讀一讀這篇文章。

來源:code.facebook.com 原文鏈接 作者:Tom Occhino

如果你對React沒有什麼瞭解,你可以先去React官方網站閱讀相關的內容。你也可以直接從React Native開始瞭解,這是我們在2015年F8展會發布的新框架。


一切從React開始

我們在兩年前就公開了我們的React框架,並且它取得了令人矚目的成長,不論是在Facebook內還是外部。今天,即使沒有任何人強迫,Facebook內部的很多web項目都已經使用React構建,它也逐步被工業界廣泛採用。工程師們選擇每天使用React來開發,因爲它使得工程師們可以把更多的時間和精力用於關注他們的產品本身,而不是應付框架帶來的各種問題。隨着我們的不斷使用,終於,我們開始瞭解是什麼使React如此強大。

React強迫我們把我們的應用劃分成多個互不相關的組件,每個組件作爲一個獨立的視圖。這使得我們更容易迭代我們的產品,因爲我們不用在改動一小部分的時候把整個系統都裝在我們腦子裏。最重要的是,React包裝了複雜而易變的DOM API,改爲提供一個聲明式的結構,使得整個程序模型變得抽象而簡單。我們發現當我們使用React來構建網頁時,我們的代碼變得十分可預測。這種可預測性使得我們在快速的迭代產品時更多的信任已有的代碼,最終我們的應用程序也變得更爲可靠。更進一步,不僅僅擴大我們的應用規模變得更容易了,我們的團隊規模也更容易進行調整。

我們一起對web產品經快速迭代後,我們已經可以用React去創建一些棒極了的產品,包括Facebook.com的很多組件。在此基礎上,我們還構建了一些Javascript頂層的框架,例如Relay,這使得我們的數據獲取流程也變得更爲簡單。當然,web並不是唯一的目標,Facebook也有一些被廣泛使用的Android和iOS應用,是基於一些完全不相關的技術棧來構建的。不得不爲每個平臺去構建App使得我們的工程師團隊不得不被分隔成幾個部分去運作,而這還不是移動應用開發唯一的難點。

爲什麼原生開發如此困難

有很多關於原生開發環境和web開發比起來難的多的解釋。舉例來說,在屏幕上去佈局一個東西就十分困難。我們往往不得不自己去計算視圖的大小和位置。我們也沒辦法像網站開發那樣用React或Relay來簡化我們的開發流程或者擴大我們的工程師團隊。而且對我們來說遷移到移動平臺最痛苦的事情,就是它大幅的降低了我們的開發效率。

在開發Web應用時,我們只需要保存我們的文件,然後在瀏覽器中點擊刷新,就可以看到改變的結果。而在原生開發的過程中,我們每次改動都得重新編譯和構建,即使我所做的僅僅是把一個文本框在屏幕上挪動了幾個像素。這使得我們的工程師在做很多工作的時候變得更加緩慢,尤其是當一個大工程的編譯特別的慢的時候。爲原生開發還使得我們爲新功能進行測試變得十分困難。在Facebook,我們一個網站可能每天就要發佈兩次,這樣我們幾乎立刻就能獲得實驗反饋。而在移動設備上,我們經常要等上幾個星期甚至是幾個月來等待Alpha/Beta測試的結果。因爲“跑的快”是Facebook的團隊基因,然而在移動設備上我們實在沒法和web上跑的一樣快。那我們爲什麼一開始要放棄用web呢?

我們現在爲不同平臺單獨開發原生APP,最重要的原因是我們能創造最佳的用戶體驗,並且能和這個平臺的習慣保持一致。


爲什麼原生開發如此必要

即使開發原生APP要耗費更多的時間,但也有很多因素導致我們通過原生應用可以給用戶在移動平臺帶來比web更好的用戶體驗。譬如說,我們可以使用原生平臺特有的UI組件,譬如地圖、日期選擇器、開關,還有導航棧。雖然在web上重新實現這些組件是可能的,但我們至今爲止並沒有在web上取得和原生完全一樣的感受,並且他們也不會隨着平臺的進步而自動更新。我們也很難在web上構建複雜的手勢識別系統,我們甚至還沒有一個適當的工具或者開發指南來幫助我們構建這樣一個系統。

在web上,我們也沒有一個足夠完善的線程模型,所以我們很難利用多線程並行執行工作。我們可以用web的Worker機制在後臺執行一部分程序邏輯,但依然無法去做一些高負荷的數值計算,譬如在主線程以外的地方去進行圖片解碼、文本佈局等等。這可能是開發一個高性能和快速響應的web app最大的難點。

將兩個世界合二爲一?

我們最夢寐以求的事情,就是既能具備原生應用的用戶體驗,又能獲得我們用React開發web應用的開發體驗。要想達到這樣的目標,我們有幾條路可以走:

  1. 使用WebView

    最簡單的辦法就是在原生包裝的應用程序中,插入一個WebView。我們幾年前就開始做這樣的嘗試,並且我們確實認爲這個方法不錯。儘管我們的實現還達不到我們想要的規模化和性能,這種方法是最靈活的,並且能沿用全部web開發的習慣,譬如React的各種好處和web的快速迭代流程。但不幸的是,因爲所有的渲染都由web相關的技術來完成,我們依然無法得到一個真正原生的用戶體驗。

  2. 移植React的原生版本

    把React移植到原生也是一個好主意。實際上,我們在iOS平臺上已經這麼做了,這個項目叫做ComponentKit,這也是我們昨天在F8展會上開源的項目。用ComponentKit,你可以獲得React所有的好處,尤其是聲明式的、可預測的UI。我們還能獲得原生開發環境的各種強大優勢,使用平臺獨有的組件和複雜的手勢處理,或者異步的進行圖片解碼、文本佈局、和渲染等等。不僅如此,因爲ComponentKit用了flexbox作爲佈局方案,你不再需要自行去管理應用中各項視圖的位置,所以你的代碼最終能變得簡潔而易於維護。

    不過這個方案也有幾處不太重要的負面影響。首先,它是iOS獨有的,所以如果我們想在Android上獲得一樣的好處,我們只能去創造一個獨立的實現,然後教會工程師怎麼去用它。並且,我們也沒辦法同時使用我們爲web頂層構建的各種工具,譬如幫助我們解決了規模性的數據獲取的許多痛點的Relay。最重要的是,我們沒能改善開發速度中最大的問題——我們還得每次修改之後,重新編譯和構建工程。

  3. 用腳本封裝原生

    如果我們用JavaScript去調用原生API,我們應當能獲得原生平臺的所有強大之處,同時還能享受快速迭代和使用我們現有JavaScript上基礎設施的好處。不僅如此,因爲基於JavaScript構建,我們應當能使得這樣技術棧跨平臺。這聽起來恰好是我們要的全部,而且毫不意外有成千上萬的框架正在這麼幹,然而實際上問題並沒有被直截了當的解決。

用腳本封裝原生是一件需要技巧的事情

如果我們只是同步的在原生環境和解釋環境之間調用,我們的UI線程很可能會被JavaScript執行阻塞住。要提升界面的響應效率,我們知道我們必須把JavaScript放到主線程之外執行,但這麼做其實很困難。最直接的困難就是資源訪問競爭。如果我們的JavaScript訪問什麼正好在被別的線程用的東西(譬如一個渲染的View的尺寸),系統就只能加鎖來確保方案安全,而這又會導致UI線程的卡頓。還有一個問題在於每次原生和JavaScript虛擬機之間互相訪問,在訪問過程中都會帶來極大的開銷。如果我們要經常跨線程訪問,我們不得不一次又一次的經歷這種開銷。

所以如果我們不找到一個正確的辦法,我們的應用可能比我們整個用原生寫或者整個用JavaScript寫還要糟糕的多。我們不能只是把用戶接口API又同步的封裝了一遍然後就期待能獲得一個流暢的、和原生APP一樣的體驗。我們必須要改變一些基礎層次的設計來確保我們的系統傳遞消息永遠是異步的,這樣我們就可以把這些消息以一定的單位來打包發送,來儘可能減少一些跨線程交互的開銷。

幸運的是,React恰好給了我們一個適當的模型來達到這個結果


引入React Native

因爲React組件本來就被設計爲一個純粹的、無副作用的函數,函數返回每一個時刻當時的View狀態,這樣我們無需讀取底層View的狀態就可以爲它寫入新的狀態。在瀏覽器環境裏,React使用一個非阻塞的方式來維護DOM,但React最棒的地方在於它其實可以構成一個抽象的概念,而不是死死的綁定在DOM上。React可以綁定到任何必要的視圖系統上,譬如iOS的UIKit等等。

這意味着我們只要很少的工作就可以用Github上已有的React來構建真正原生的移動應用。移動環境唯一的區別在於不同瀏覽器裏的React用div和span標籤來渲染,我們用一個植入的JavasScriptCore來運行JavaScript,然後渲染平臺獨有的組件。

這個方案帶來的一個巨大好處在於我們可以逐步的進行方案替換。我們既可以在新項目中直接基於React構建,也可以在舊項目的合適部分中去嘗試性的使用它。正如我們剛開始在Facebook.com中使用React也僅僅是在某些地方,我們也沒必要爲了React的好處而把所有Facebook的所有應用重寫一遍。

這個方案真的可行

我們現在已經在Facebook的產品線上使用了React Native。儘管還有一堆工作需要進行,它真的讓我們感覺不錯。需要注意的是我們不再強調所謂的“一次編寫,隨處運行”。不同的平臺應該有不同的外觀、感覺、功能等等。我們仍然需要爲不同的平臺去做一些額外的工作。但是我們只需要同一幫工程師就可以覆蓋到不同的平臺,也不需要去學習各個平臺自己的技能樹。我們把這個方案叫做“一次學習,隨處編寫”。


如果你有一個iPhone設備,你已經可以從App Store中下載到我們用React Native構建的一些APP。Facebook Groups是一個混合開發的應用,一部分由原生代碼構建,一部分由React Native的JavaScript代碼構建。而Facebook Ads Manager則是一個徹底用React Native構建的應用。

開源

在Facebook,我們的使命之一就是讓世界變得更加開放和連接。所以我們也希望通過開源來爲這個使命貢獻。React Native並不例外。我們意識到工程師組織的難題並不是Facebook獨有的問題,而且我們也希望儘可能的公開開發,與面臨相似挑戰的人進行合作。

今天,我們高興的宣佈React Native的iOS版本已經在Github公開。安卓支持也即將到來。我們也在持續努力推進React的web版本,但我們希望儘早發佈這個初始的iOS版本,這樣我們就可以從其它對此方案感興趣的人那裏獲得反饋。記住現在在React Native中還有很多的問題或者尚未實現的部分,我們非常歡迎您的反饋建議,我們也非常期待看到您用React Native所構建出的App!

原文連接:http://bbs.reactnative.cn/topic/14/react-native-%E6%8A%8A%E7%8E%B0%E4%BB%A3web%E7%A7%91%E6%8A%80%E5%B8%A6%E7%BB%99%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91%E8%80%85

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章