從前,若是咱們打算實現某個需求,一般須要三種程序員(IOS, 安卓,前端)寫三份代碼。這就帶來了很是大的開發成本,因此業界也一直在探索跨平臺方案——從最先的H5, Hybrid 到如今的weex, React Native。這些方案的本質目的都是,一套代碼,多端運行。javascript
早期H5和Hybrid方案的本質是,利用客戶端App的內置瀏覽器(也就是webview)功能,經過開發前端的H5頁面知足跨平臺需求。css
該方案提高開發效率,同時也知足了跨端的需求。但有一個問題就是,前端H5的性能和客戶端的性能相差甚遠。html
因而後來, 業界繼續探索能夠媲美原生體驗app的方案,好比說WEEX 。前端
WEEX依舊採起前端H5頁面進行開發,同時app在終端的運行體驗不輸native app。便可以保證快速響應需求,又能夠保證用戶體驗。vue
那麼WEEX是如何實現的?java
本質來講,WEEX是用客戶端Native 的能力,去作了部分瀏覽器(webview)的工做。node
在2016年2月, WeexSDK 發佈了v0.10.0版本,在這個版本里面,集成了v2 版本的Vue。程序員
爲啥是Vue 2.x 版本呢?web
Vue 2.x加入了 Virtual-DOM 和預編譯器的設計,使得該框架在運行時可以脫離 HTML 和 CSS 解析,只依賴 JavaScript;同時 Virtual-DOM 也使得 Vue 2.x 渲染成原生 UI 成爲了可能。算法
咱們先來看一下 weex 的總體框架。
從上圖中能夠看到weex的大體工做流程:
JS Bundle
,而後在客戶端本地執行該JS Bundle
JS Bundle
JS Bundle
,和瀏覽器的過程相似,JS Bundle
的代碼被執行,生成VNode 樹進行patch,找出最小操做DOM節點的操做,把對DOM節點的操做轉變爲Native DOM API
, 調用WXBridge
進行通訊WXBridge
將渲染指令分發到native(Andorid、iOS)渲染引擎,由native渲染引擎完成最終的頁面渲染看完上述總體流程後,能夠大體理解爲什麼WEEX能夠達到媲美原生的體驗,由於其頁面渲染並非像H5方案同樣使用瀏覽器的渲染能力,而是原生渲染,因此本質上渲染出來的頁面就是一個native頁面。
下面會具體的介紹下面幾個過程:
JS bundle
是前端同窗寫好代碼後打包出來的dist
.
前端同窗能夠在.vue
的單文件中,寫<template>
,<style>
和<script>
標籤,而後把這些標籤轉換爲JS Bundle
用於部署在服務端,以後客戶端會去請求這些JS Bundle
。
好比說,下圖中左邊是vue源代碼,右邊是打包出來到JS Bundle
熟悉Vue 原理的同窗清楚,上面右邊其實就是Vue打包生成的render
函數。
JS代碼比較簡單,邏輯就不介紹了。接下來重點介紹,當客戶端獲取到如上圖右側的js bundle後,如何進行加載、渲染以及後續的相關邏輯執行。
weex在真正打開一個頁面以前,會先作一些準備的初始化工做,這一點有一點像微信小程序。在初始化階段,WEEX SDK 會初始化好下面幾樣東西:
js
的執行環境——js Core
或者是 v8
weex-vue-framework
的代碼WXBridge
以下圖所示:
在初始化階段, WEEX SDK 會準備好一個js的執行環境。由於咱們是要在客戶端跑js
代碼的,因此須要一個js執行環境,這個執行環境相似於瀏覽器的v8
引擎, 在IOS 上,則是客戶端自帶的 js core
。
這個js執行環境
,能夠當作是一個在客戶端上的沙盒,或者是一個虛擬機。
爲了提高性能,js 執行環境只用在初始化的時候初始化一次,以後每一個頁面都無須再初始化了。也就是說無論客戶端打開多少個weex頁面,多個頁面的 JS 都是跑在同一個js執行環境中的。
weex-vue-framework
框架 是什麼呢?
你能夠把 weex-vue-framework
框架當成被改造的Vue.js
。語法和內部機制都是同樣的,只不過Vue.js
最終建立的是 DOM 元素,而weex-vue-framework
則是向原生端發送渲染指令,最終渲染生成的是原生組件。
同時,Weex
爲了提升Native
的極致性能,作了不少優化的工做。前端優化性能時,會把業務代碼和 vue.js
這類的依賴包分開打包,一個份是業務代碼,一份是打包的框架依賴。
weex 把weex-vue-framework
這類框架依賴內置到了SDK中,客戶端訪問Weex頁面時,只會網絡請求JS Bundle。因爲JSFramework在本地,因此就減小了JS Bundle的體積,每一個JS Bundle均可以減小一部分體積,從而提高了性能。
WXBridge
是 weex 實現的一種 js 和 客戶端通訊的機制。
js 執行環境和客戶端是隔離的,爲了和外界客戶端的世界通訊,須要有一個通訊的橋樑。weex 實現了 WXBrigde
, 主要經過 callJS
和 callNative
兩個核心的方法,實現 js
代碼和客戶端代碼雙向通訊。
在完成了上面的初始化以後,weex已經作好了準備,只等着下載 JS bundle
就可開始渲染頁面了。
實際上當WEEX SDK獲取到JS Bundle後,第一時間並非立馬渲染頁面,而是先建立WEEX的實例。
每個JS bundle
對應一個實例,同時每個實例都有一個instance id
。
咱們上文中說過,因爲全部的js bundle
都是放入到同一個JS執行引擎中執行,那麼當js執行引擎經過WXBridge
將相關渲染指令傳出的時候,須要經過instance id
才能知道該指定要傳遞給哪一個weex實例
在建立實例完成後,接下來纔是真正將js bundle交給js執行引擎執行。
在實例建立完成後,接下來就是執行JS bundle
了。JS bundle
的結果是生成Virtual DOM ,而後去patch 新舊 Vnode 樹,根據diff
算法找出最佳的DOM操做,惟一和瀏覽器不一樣的是,調用的是 Native app api ,而不是瀏覽器裏面對DOM節點增刪改查的操做。
bundle.js
會執行new Vue()
建立一個vue
組件,並經過其render
函數建立VNode節點,即virtual dom節點 , 像下面這樣:
{
tag: 'div',
data: {
staticStyle: { justifyContent: 'center' }
},
children: [{
tag: 'text',
data: {
staticClass: 'freestyle'
},
context: {
$options: {
style: {
freestyle: {
textAlign: 'center',
fontSize: 200
}
}
}
},
children: [{
tag: '',
text: 'Hello World!'
}]
}]
}
複製代碼
生成了VNode以後,接下來須要將VNode同步到真實的Dom之上,該過程在Vue.js
中被稱爲patch
,patch
會比較新舊VNode之間的差別,最小化操做集。最後再將Virual Dom總體更新到真實Dom之上。
在執行 patch 以前的過程都是 Web 和 Weex 通用的,後面的流程就不同了,由於客戶端沒有對 DOM 增刪改查的API,因此這些更新的操做,須要通過weex-vue-framework
的處理,通通映射爲客戶端的Native DOM API
weex終端的執行引擎在執行到Native DOM API
後,WXBridge
將Native DOM API
轉化爲Platform API
Platform API
是 Weex SDK 中原生模塊提供的,不是 js 中方法,也不是瀏覽器中的接口,是 Weex 封裝的一系列方法。
本人是一枚前端同窗,不太瞭解客戶端的頁面是如何寫出來的,問了客戶端的大佬後,瞭解以下:
對於前端同窗來講,寫一個相似上面的框內帶文字的效果很是簡單:
.text {
// css 樣式
}
哈哈哈哈
複製代碼
只須要 html
+ css
就能夠實現。
對於客戶端的同窗,則須要寫很是多的代碼來實現:
因此,weex 會把上面一些系列複雜的代碼封裝好一個個現成的方法。
原生渲染器接收上層傳來的渲染指令,而且逐步將其渲染成原生組件。
這樣,咱們在js中的<div>
, <p>
標籤,就一一對應到了客戶端的原生標籤。
這個過程不是分階段一個一個執行的,而是能夠實現「流式」渲染的,有可能第一個<div>
的原生組件還沒渲染好,<text>
的渲染指令又發過來了。當一個頁面特別大時,能看到一塊一塊的內容逐漸渲染出來的過。
經過前文的介紹,相信你們對WEEX有了一個初步的系統認識。簡單來講,WEEX放棄了傳統的Webview
,而是搭建了一個native化的瀏覽器
,由於用native的方式實現了一個瀏覽器的大部分核心組成成分:
另外爲了保證整個SDK的運行效率,SDK維護了三個線程:
以上就是WEEX SDK的大體框架和核心邏輯