1. 程式人生 > >小程式框架原理之渲染流程及通訊流程

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

MINA

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

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

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

模式。

wxml的真實面目

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

探尋

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

接下來一步步找到小程式 wxml 渲染完成的真實樣子,工具選單欄點選微信開發者工具,選擇除錯微信開發者工具。開啟的控制檯可以除錯整個微信開發者工具,用除錯箭頭指向小程式內容區域,這時可以看到小程式檢視層是被巢狀在 webview

iframe 內。

但是當我們點開 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.js 和 WAWebview.js 的程式碼作為學習參考。