近些年來,前端領域的跨端技術愈來愈多了:react native、weex、flutter、electron、kraken 等等。css
那麼多跨端方案,他們有沒有通用的思路?咱們能不能從這麼多方案中找出本質的原理?前端
本文會嘗試探究探究如下問題:vue
咱們知道,cpu 有不一樣的架構和指令集,上層也有不一樣的操做系統,一個系統的可執行文件在另外一個系統上就是不可執行的,好比 windows 的 exe 文件在 mac 上就不能直接執行。不一樣的系統就是不一樣的運行平臺。可執行文件是不跨平臺的。java
不一樣平臺提供的 api 不一樣,因此代碼邏輯可能也不一樣,須要不一樣平臺單獨維護代碼。這樣就帶來了幾個問題:node
因此出現了跨平臺的一些技術,目標是一份代碼跑在任意平臺。react
咱們先來看一些各領域的跨平臺方案:ios
操做系統不一樣,瀏覽器上跑的網頁的代碼確實同一份。瀏覽器就是一種歷史悠久的跨平臺方案。c++
網頁跨平臺不意味着瀏覽器也是跨平臺的,瀏覽器的可執行文件仍是每一個平臺單獨開發和編譯的,可是他們支持的網頁解析邏輯同樣,這樣上面跑的網頁就是跨平臺的。web
瀏覽器提供了一個容器,屏蔽了底層差別,提供了統一的 api(dom api),這樣就能夠實現同一份代碼跑在不一樣平臺的統一的容器裏。這個容器叫作瀏覽器引擎,由 js 引擎、渲染引擎等構成。docker
docker 是一種虛擬化技術,能夠在操做系統之上加一個虛擬層,在這層之上劃分一到多個容器,容器裏再去跑系統、app,這樣能夠實現硬件和軟件的分離,動態分配硬件資源給容器,而且方便 app 運行環境的總體遷移(保存成鏡像)。
docker 很明顯也是一種跨平臺技術,同一個鏡像能夠跑在任何操做系統的 docker 上。只要不一樣操做系統實現一樣的容器便可。
java 是一門編譯 + 解釋的語言,java 源碼編譯成字節碼,而後字節碼直接在 vm 上解釋執行。
java 爲何這麼火呢?主要是由於跨平臺。
c、c++ 這種語言寫的代碼須要編譯成不一樣操做系統上的可執行文件來跑,並且每一個平臺的代碼可能還不同,須要寫多份。
java 由於提供了 jvm 容器,只要把源碼編譯成 jvm 能解釋的字節碼就好了,並且 jdk 提供了統一的 api,分別由不一樣操做系統的底層 api 來實現,這樣對於 java 代碼來講,不一樣操做系統的代碼是一致的。
jvm 也是經過容器的技術實現了一份代碼跑在多個平臺,並且 jre 提供了統一的 api,屏蔽掉了底層的差別。
node 和 deno 也是跨平臺的技術,經過提供一套一致的 api,讓其上的 js 代碼能夠跨平臺。這些 api 也是不一樣平臺各自實現的。
electron 內置了 chromium,併爲其注入了 node 的 api 和一些 GUI 相關的 api,是基於兩大跨平臺技術綜合而成的跨平臺方案。基於這些方案的組合使得 electron 支持用前端技術開發桌面端。
跨平臺方案的優勢很明顯,就是一份代碼跑在不一樣平臺的一樣的容器內,不用不一樣平臺單獨開發,節省成本。
可是跨平臺方案也有缺點:
由於多了一層容器,因此性能相比直接調用系統 api 會有所降低
爲了實現多平臺的一致,須要提供一套統一的 api,這套 api 有兩個難題:
api 怎麼設計。要綜合不一樣平臺的能力,取一個合適的集合來實現。設計上有必定難度。node、deno、java 都抽象了操做系統的能力,提供了各自的跨平臺 api
部分 api 很難作到多平臺的一致性
當容器沒有提供的能力須要擴展的時候比較麻煩,好比 js 引擎的 bridge、 jvm 的 jni、node 的 c++ addon 等都是爲這個容器擴展能力的方式
跨平臺指的是跨操做系統,而跨端是指客戶端。
客戶端的特色就是有界面、有邏輯,因此包含邏輯跨端和渲染跨端。主要的客戶端有 web、安卓、ios、iot 設備等。
如今主流的跨端方案有 react native、weex、flutter、kraken 以及各家自研的跨端引擎等。
跨端包括邏輯跨端和渲染跨端,rn 的邏輯跨端是基於 js 引擎,經過 bridge 注入一些設備能力的 api,而渲染跨端則是使用安卓、ios 實現 react 的 virtual dom 的渲染。
其中 native api 和組件(灰色畫出的部分)並無作到雙端一致,並且有的時候擴展圖中灰色部分須要原生配合,混雜 rn 代碼和本身擴展的代碼致使代碼比較難管理。最著名的事件就是 airbnb 從最大的 react native 支持者到棄用 react native。
weex 也是相似的思路來實現跨端的,不過他對接的上層 ui 框架是 vue,並且努力作到了雙端的組件 和 api 的一致性(雖而後續維護跟不上了)。架構和上圖相似。
flutter 是近些年流行的跨端方案,跨的端包括安卓、ios、web 等。它最大的特色是渲染不是基於操做系統的組件,而是直接基於繪圖庫(skia)來繪製的,這樣作到了渲染的跨端。邏輯的跨端也不是基於 js 引擎,而是自研的 dart vm 來跨端,經過 dart 語言來寫邏輯,
跨端包括兩部分,渲染跨端和邏輯跨端。有時候只須要渲染跨端、有時候只須要邏輯跨端,有的時候須要完整的跨端引擎,這 3 種狀況都有各自的適用場景。
kraken 就是一個跨端渲染引擎,基於 flutter 的繪圖能力實現了 css 的渲染,實現了渲染的跨端。
跨端引擎很依賴底層實現的組件和 api,用開源方案也同樣得擴展這部分,因此有必定規模的團隊都會選擇自研。
自研跨端引擎會和 rn、weex 不一樣:
渲染部分不須要實現 virtual dom 的渲染,而是直接對接 dom api,上層應用基於這些 dom api 實現跨端渲染。這樣理論上能夠對接任意前端框架。
邏輯部分也是基於 js 引擎,經過 binding 直接注入一些 c++ 實現的 api,或者運行時經過 bridge 來注入一些安卓、ios 實現的 api。
自研跨端引擎的好處是組件和 api 能夠本身擴展,更快的響應業務的需求。其中組件和 api 的雙端一致性,以及統一的 api 的設計都是難點。
其實跨端和跨平臺的思路相似,都是實現一個容器,給它提供統一的 api,這套 api 由不一樣的平臺各自實現,保證一致的功能。
具體一些的話,跨端分爲渲染和邏輯跨端,有的時候只須要單獨的渲染跨端方案(好比 karen)和邏輯跨端方案,有的時候須要完整的跨端引擎。
weex、react native 的渲染部分都是經過實現了 virtual dom 的渲染,用安卓、ios 各自的渲染方式實現,邏輯部分使用 js 引擎,經過 bridge 注入一些安卓、ios 的 api。
flutter 則是直接使用 skia 繪圖庫繪製,而且邏輯跨端使用 dart vm。
可是無論具體實現怎樣,思路都大同小異:跨端引擎須要實現一個渲染引擎、實現一個 vm,基於這套架構實現各類組件和 api,跨端容器上層對接一個 ui 框架,再上層的業務代碼能夠基於容器的 api 實現跨端的渲染和邏輯
這兩天 web container 比較火,其實也是一種跨平臺技術,它是在瀏覽器裏面實現的容器,經過 wasm 實現了 node 的 api,這樣在這個容器裏面能夠跑 node 代碼。其實思路比較常見,可是是一個新場景。
瀏覽器容器之上又跑了個容器,容器套娃。
咱們聊了跨平臺和跨端的區別,跨平臺是指跨操做系統,而跨端則是指跨客戶端。
跨平臺技術聊了 docker、瀏覽器、jvm、node、deno、electron、web container 等,他們都是跨平臺(操做系統)的方案,跨平臺有優勢也有缺點,缺點就在於 api 的設計比較難,node、deno、java 等都有本身的一層 api 設計;api 一致性的保障也比較困難;其次就是擴展方式複雜一些(jvm 的 jni、node 的 c++ addon 等)。
跨端方案聊了 react native、weex、flutter、kraken 等,有的是綁定了 react、vue 等前端框架,直接從 virtual dom 渲染,有的是實現了 dom api,能夠對接任意前端框架。固然能夠單獨作渲染或邏輯跨端。渲染跨端或者用安卓、ios 提供的方式,或者本身繪製,邏輯跨端或者用 js 引擎(能夠對接前端框架)或者用 dart vm。
但願這篇文章可讓你理解跨端和跨平臺的容器的思路和優缺點,遇到一些新技術(好比 web container)也能快速的理解。