小程式框架原理之渲染流程及通訊流程

MINA

MINA 是在微信中開發小程式的框架。其目標是通過儘可能簡單、高效的方式讓開發者可以在微信中開發具有原生 APP 體驗的服務。

MINA 提供了自己的視圖層描述語言 WXMLWXSS,以及基於 JavaScript 的邏輯層框架,核心是一個響應的數據綁定系統。整個系統分為視圖層(View)和邏輯層(App Service),並在視圖層與邏輯層間提供了數據傳輸和事件系統,可以讓開發者可以方便的聚焦於數據與邏輯上。

MINA 讓數據與視圖保持同步非常簡單。當做數據修改的時候,只需要在邏輯層修改數據,視圖層就會做相應的更新。MINA 是騰訊給微信小程式命名的框架,實際上應用的是目前業界最著名的 MVVM 模式。

wxml的真實面目

我們都知道小程式提供了很多方便快捷的自定義組件(標籤),但你知道小程式的這些組件編譯過後會渲染成什麼嗎?先說答案,其實 wxml 經過編譯後會渲染成 html 。很簡單的一點,你發現在小程式內編寫 html 標籤,最終也可以運行。

探尋

光說可能體會不到,下面開始探尋小程式真實渲染的樣子。先看下開發者工具內 wxml 的內容,待會和真實渲染的內容做對比。

接下來一步步找到小程式 wxml 渲染完成的真實樣子,工具菜單欄點擊微信開發者工具,選擇調試微信開發者工具。打開的控制台可以調試整個微信開發者工具,用調試箭頭指向小程式內容區域,這時可以看到小程式視圖層是被嵌套在 webviewiframe 內。

但是當我們點開 iframe 是無法查看到裡面內容的。如果想要查看調試 webview,只需選中 webview 打開它的調試工具即可,在控制台輸入以下程式碼:

$$('webview')[0].showDevTools(true)

可以看到又打開了一個調試窗口,這裡面就是小程式視圖層渲染的真實樣子:

可以看到結構和 wxml 里的內容幾乎一模一樣,只是 topbar 變成了 wx-topbarview 變成了 wx-view等。這些都是內部實現的一套對應小程式標籤的 webComponent 組件,而 webComponent 實際渲染出來還是 html 標籤。

轉換過程

轉換過程是微信開發者工具內部通過一個可執行編譯工具實現對小程式文件轉換。在微信開發者工具控制台輸入 openVendor() 會打開一個文件夾,裡面存放著微信的基礎庫及工具,在裡面可以找到 wcc.exewcsc.exe 執行文件,分別對應 wxmlwxss 的文件轉換。

該工具可以單獨對小程式文件進行轉換,使用方法 ./wcc -d wxml文件路徑 >> 輸出路徑。例如,將工具複製到一個文件夾內,再將一個 wxml 放入該文件夾內,命令行輸入 :

./wcc -d index.wxml >> index.js

可能有人很好奇為什麼是生成 js 文件,而不是 html 文件。原因很簡單,因為需要處理 wxml 的動態綁定數據。看看這個 js 文件生成的是什麼:

因為這些都是混淆壓縮過的程式碼,基本沒有可讀性。這裡只需要注意一個函數就好,那就是 $gwx。這是個很關鍵的函數,它的作用是生成虛擬dom樹,用於渲染真實節點。

接下來回到 webview 調試窗口,在 head 內找到這段插入的 script 標籤程式碼:

有沒有很熟悉,沒錯,就是和上面轉換後的程式碼是同一個東西。也就是說,我們的 wxml 文件通過編譯,最終在視圖層中執行的就是這段 js 程式碼(這裡只是可以大概這麼理解,實際需要向邏輯層獲取數據才能渲染頁面)。控制台輸入 $gwx 發現這個函數存在,那麼這個函數如何生成虛擬dom呢?$gwx 函數的第一個參數接收一個路徑參數,這個路徑就是 wxml 文件路徑,此時在控制台輸入:

let generateFunc = $gwx('./pages/index/index.wxml')
generateFunc()

這時頁面虛擬dom就生成出來了:

單純調用 generateFunc 生成出來的虛擬dom是沒有動態綁定數據的,如果想要動態的綁定數據,在調用 generateFunc 時傳入一個數據對象。但是數據全在邏輯層里,這時就需要進行通訊了。

數據通訊

首先要知道小程式時運行在基礎庫之上的,但它們都是壓縮打包好的,後面找到反編譯出來的基礎庫程式碼,其中最重要的就是 WAService.jsWAWebview.js,它們分別是視圖層和邏輯層的核心實現。

它們之間需要一個橋樑來進行通訊,那就是 JS BridgeJS Bridge 提供調用原生功能的介面(攝影機,定位等),它的核心是構建原生和非原生間消息通訊的通道,而且這個通訊的通道是雙向的。通過 JS Bridge 的發布訂閱方法,視圖層和邏輯層進行數據通訊。

通訊流程

接下來看看視圖層和邏輯層的交互流程:

  1. wxml 轉換成對應的 js 文件,等待生成虛擬dom函數 $gwx 準備完成,使用 dispatchEvent 通知 WAWebview
  1. WAWebview 監聽到 generateFuncReady 事件觸發,使用 WeixinJSBridge.publish 向邏輯層通訊。
  1. 邏輯層處理邏輯,也就是我們平常寫的小程式 js 文件里的東西,然後通過 JS Bridge 通知並返回數據給視圖層。

  2. 視圖層接收到數據,將數據傳入生成虛擬dom的函數內,渲染頁面,當然小程式也有相應的diff演算法。

例如在 wxml 中綁定一個動態數據 title,視圖層接收到數據後,重新生成虛擬dom

generateFunc({
  title'標題'
})
  1. 初始化完成後,就會走對應的其他生命周期,或者用戶觸發事件,數據都會在邏輯層處理完成後通過 JS Bridge 通知到視圖層,視圖層再次調用生成虛擬dom的函數,更新頁面。

wxss如何工作

wxss 工作原理和 wxml 差不多,都是通過工具轉換為 js。為什麼又是轉換成 js,因為有 rpx 單位,需要根據手機尺寸進行設置 px

wcsc.exe 轉換命令如下:

./wcsc -js index.wxss >> index.js

可以看到文件開頭就是對 rpx 的轉換

之後創建 style 標籤,動態添加到視圖層中

最後

附上 WAService.jsWAWebview.js 的程式碼作為學習參考。

Tags: