微信小程式開發詳解(微信小程式架構原理)

(文末福利:小程式開發利器)

作者:billgong,騰訊IEG前端開發工程師。

微信小程式,簡稱小程式,英文 mini program。是一種不需要下載安裝即可在微信中使用的應用,使用者掃描小程式碼或搜尋小程式即可開啟,觸手可及,用完即走,不用關心是否安裝太多應用的問題。

小程式技術演進

內部開放微信原生能力

   

使用 WeixinJSBridge 預覽圖片

此類 API 最初是提供給騰訊內部一些業務使用,很多外部開發者發現了之後,依葫蘆畫瓢地使用了,逐漸成為微信中網頁開發的事實標準。

JS-SDK 釋出

2015 年初,微信釋出了一整套網頁開發工具包,稱之為 JS-SDK,開放了拍攝、錄音、語音識別、二維碼、地圖、支付、分享、卡券等幾十個 API。讓所有開發者都可以使用到微信的原生能力。

   

使用 JS-SDK 呼叫圖片預覽元件

JS-SDK 解決了移動網頁使用微信能力不足的問題,通過暴露微信的介面使得 Web 開發者能夠擁有更多的能力,然而在更多的能力之外,JS-SDK 的模式並沒有解決使用移動網頁遇到的體驗不良的問題。

JS-SDK 的不足

使用者在訪問網頁的時候,在瀏覽器開始顯示之前都會有一個白屏的過程,在移動端,受限於裝置效能和網路速度,白屏會更加明顯。除了白屏,影響 Web 體驗的問題還有缺少操作的反饋,主要表現在兩個方面:頁面切換的生硬和點選的遲滯感。

   

載入白屏,切換不流暢

此外一些開發者會使用 JS-SDK 做一些,比如假紅包,偽造的官方活動等。並利用 JS-SDK 的分享能力變相的去裂變分享到各個群或者朋友圈,由於 JS-SDK 是根據域名來賦予 api 許可權的,運營人員封了一個域名後,他們立馬用別的域名又繼續做壞,要知道註冊一個新的域名的成本是很低的。

那麼小程式是通過怎樣的設計來改進 JS-SDK 的體驗和管控上的不足?

小程式雙執行緒架構

具體實現上小程式採用了類 web 離線包的形式。開發上與 web 類似,門檻較低,開發效率較高。離線下載和頁面預渲染功能增強了使用者體驗,提升了載入速度,解決了 JS-SDK 載入白屏的問題 1。小程式提供了雲端更新離線包的功能,可動態更新頁面,相對於 app 的更新和釋出更為靈活。此外,小程式在離線包的基礎上對切換動畫進行優化,降低了切換頁面導致的遲滯感,緩解了切換不流暢的問題 2。

   

小程式web 離線包模式

小程式在架構方面最大的特點是採用了雙執行緒的開發模式,隔離了 JS 邏輯和 UI 渲染。小程式的渲染層和邏輯層分別由 2 個執行緒管理:渲染層的介面使用了 WebView 進行渲染,邏輯層採用 JsCore 執行緒執行 JS 指令碼。

邏輯層:建立一個單獨的執行緒去執行 JavaScript,在這個環境下執行的都是有關小程式業務邏輯的程式碼;
   渲染層
:介面渲染相關的任務全都在 WebView 執行緒裡執行,通過邏輯層程式碼去控制渲染哪些介面。一個小程式存在多個介面,所以渲染層存在多個 WebView 執行緒;
   通訊
:這兩個執行緒的通訊會經由微信客戶端(下文中也會採用 Native 來代指微信客戶端)做中轉,邏輯層傳送網路請求也經由 Native 轉發,小程式的通訊模型下圖所示。

   

小程式雙執行緒架構

JS 邏輯層執行在 JSCore 中,並沒有一個完整瀏覽器物件,因而缺少相關的 DOM API 和 BOM API,無法操作頁面元素,能達到管控的目的,但也限制了開發者的許可權:

  1. 不允許開發者把頁面跳轉到其他線上網頁
  2. 不允許開發者直接訪問 DOM
  3. 不允許開發者隨意使用 window 上的某些未知的可能有危險的 API

這樣的邏輯層與 UI 層的隔離,加上小程式的稽覈和舉報機制,使得微信加強對小程式的管控,解決了問題 3。但這也使得開發者無法靈活的進行頁面渲染。

小程式頁面渲染

上面已經說了邏輯層無法操作 DOM 變更,那小程式是如何進行頁面的渲染呢?小程式基於資料驅動的架構模式,基於 Virtual Dom(React 引入,真實 DOM 的一種 JS 描述方式)的概念,業務側只需要改變資料即可引起介面變化。其中渲染層提供了帶有資料繫結語法的 WXML,邏輯層提供了setData 等等 API,開發者需要進行介面變化時,只需要通過在邏輯層執行 setData 把變化的資料通過 Native 層傳遞到渲染層,小程式會進行 Dom Diff(DOM 結構對比並進行最小化變更的演算法)等流程,最後把正確的結果更新在 Dom 樹上。

   

小程式Virtual DOM渲染

完整的通訊流程大致如下:

  1. 邏輯層呼叫宿主環境的 setData 方法。
  2. 邏輯層將待傳輸資料轉換成字串,並拼接到特定的 JS 指令碼,最後將資料傳輸到渲染層。
  3. 渲染層接收到後,WebView JS 執行緒會對指令碼進行編譯,得到待更新資料後進入渲染佇列,等待 WebView 執行緒空閒時進行頁面渲染。
  4. WebView 執行緒開始執行渲染時,待更新資料會合併到檢視層保留的原始 data 資料,並將新資料套用在 WXML 片段中得到新的虛擬節點樹。經過新虛擬節點樹與當前節點樹的 diff 對比,將差異部分更新到 UI 檢視。同時將新的節點樹替換舊節點樹,用於下一次重渲染。

小程式方案與 React Native 對比

那麼小程式與現有的混合開發技術型別的異同點在哪?尤其是與 React Native 的區別,小程式技術架構為什麼沒有使用 React Native?

混合開發技術型別

現有的混合開發型別,基於 UI 渲染的分類來看,主要有兩類:

  1. 基於 WebView UI 的基礎方案。市面上主流,例如微信 JS-SDK,通過 JSBridge 完成 H5 和 Native 的雙向通訊,從而賦予 H5 一定的原生能力。
  2. 基於 Native UI 的方案,例如 React-Native、Weex、Flutter 等。在賦予 H5 原生 API 能力的基礎上,進一步通過 JSBridge 將 JS 解析成虛擬 DOM 傳遞到 Native,並使用原生渲染。

小程式也屬於型別 1,本次我們主要以型別 2 中的 React Native 作為對比分析。

React Native 技術架構

框架

React Native 框架主要有三層:

  1. JS 層:該層提供了各種供開發者使用的元件以及一些工具庫(事件分發等)。
  2. C 層:主要處理 java/OC 與 JS 的通訊(JSBridge)以及執行 JavaScript(JS 指令碼引擎)。
  3. Native 層(Object C/Java 層):主要包括 UI 渲染器、網路通訊等工具庫。根據不同作業系統有不同的實現。

UI 渲染

React Native 基於 react 框架(Virtual Dom)來進行 UI 渲染,具體的流程大致如下:

  1. 首先 JS 層通過 JSX 編寫的 Virtual Dom 來構建 Component
  2. Native 層將其轉成真實 DOM 插入到原生 App 的頁面中。
  3. 當有變更,通過 diff 演算法生成差異物件
  4. 最終由 Native 層將差異物件應用到原生 App 的頁面元素上。

通訊

React Native 基於 JSCore 實現 js 與 java/oc 互動,具體流程大致如下:

  1. 把 JSX 程式碼解析成 javaScript 程式碼
  2. 讀取 JS 檔案,並利用利用 JS 指令碼引擎執行
  3. 返回一個陣列,陣列中會描述 OC/Java 物件,描述物件屬性和所需要執行的方法,這樣就能讓這個物件設定屬性,並且呼叫方法。
   

Reactive Native架構

React Native 優缺點

優勢

  1. 原生渲染,效能更好,使用者體驗較好;
  2. React 生態較好,對前端開發友好;
  3. hybrid 技術跨平臺開發,成本及難度低於原生;
  4. 可熱更新,能夠方便迭代。

劣勢

  1. 支援的樣式是 CSS 的子集,會滿足不了 Web 開發者日漸增長的需求;
  2. 現有能力下還存在的一些不穩定問題,比如效能、Bug 等;
  3. 把渲染工作全都交由客戶端原生渲染,會有更接近原生的體驗,但實際上一些簡單的介面元素使用 Web 技術渲染完全能勝任;
  4. React Native 之前爆出了一個開源協議問題(Facebook BSD Patents ,大致內容是使用基於 Facebook BSD Patents 協議的開源專案的開發者,未來要是因為專利問題與 Facebook 產生糾紛,那麼 Facebook 將有權停止你使用該開源專案),這對於之後也是存在隱患的。

小程式不選擇 React Native 原因

據小程式開發人員告知的原因如下:

  1. React Native 只支援 CSS 的子集,作為一個開放的生態,需要告知開發者哪些 CSS 屬效能用,哪些不能用,這樣的開發體驗較差;(對應上面的劣勢 1
  2. React Native 本身存在一些問題,這些依賴 RN 的修復,同時這樣就變成太過依賴客戶端發版本去解決開發者那邊的 Bug,修復週期太長。(對應上面的劣勢 2
  3. React Native 前陣子還搞出了一個開源協議問題,來說也是存在隱患的。(對應上面的劣勢 4

小程式與 React Native 相同點

  1. 都具有 hybrid 技術的優點:接近原生的體驗,跨平臺開發
  2. 使用 Web 相關技術框架來編寫業務程式碼,React Native 為 React 框架,小程式為小程式開發框架。
  3. 各自實現了跨語言通訊方案完成 Native(Java/Objective-c/…)端與 JavaScript(小程式中為渲染層和邏輯層)的通訊

小程式與 React Native 不同點

小程式使用瀏覽器核心 WebView 來渲染介面(小部分原生元件由客戶端參與渲染),介面主要由成熟的 Web 技術渲染,輔之大量的介面提供豐富的客戶端原生能力,而 React Native 是客戶端原生渲染。理論上 React Native 相對於 WebView 的效能更好,但小程式的類 web 開發對開發來說入門相對簡單,像是一種開發效率與效能的雙刃劍。

小程式開發注意事項

基於上面的架構分析,我們在開發中需要注意是:

  1. 避免使用操作操作 DOM 的 npm 包。由於邏輯層和渲染層隔離,邏輯層無法操作 DOM/BOM API,所以需要使用 DOM/BOM API 相關的 npm 包和庫中不可使用。
  2. 避免頻繁呼叫setData。由於setData中的資料不僅需要通過 Native 層傳遞到渲染層,通過 DOM diff 演算法等渲染成最終頁面,所以需要儘量減少setData的使用以避免效能問題。
  3. 避免setData傳遞大量的新資料。資料的傳輸會經歷跨執行緒傳輸和指令碼編譯的過程,當資料量過大,會增加指令碼編譯的執行時間,佔用 WebView JS 執行緒,從而影響到最終的渲染效能。

參考文件

  1. 小程式簡介 | 微信開放文件小程式簡介 | 微信開放文件
  2. React-Native與小程式的底層框架比較 - 雲 社羣 - 騰訊雲
  3. 微信小程式原理分析和多端小程式架構原理(應該是全網最全了) | 懸筆e絕的個人部落格
  4. 小程式架構設計(一) | 微信開放社羣
  5. 小程式架構設計(二) | 微信開放社羣

福利時間

抽5位朋友送出《小程式開發原理與實戰》,騰訊一線專家帶你學習小程式開發,乾貨滿滿!戳這裡: 福利 參與!