微信小程序底層原理剖析
最近公司開發了好幾款微信小程序,今天就做一些簡單的原理分析,我們開始吧!
從兩大線程說開
小程序由兩大線程組成:負責界面的線程(view thread)和服務線程(appservice thread),各司其職由互相配合。兩個線程分別用於渲染層和邏輯層,渲染層的界面使用了 WebView 進行渲染,通過邏輯層代碼去控制渲染哪些界面,如果一個小程序存在多個界面,則渲染層存在多個 WebView 線程;邏輯層採用一個單獨的 JsCore 線程運行 JS 腳本,在這個環境下執行的都是有關小程序業務邏輯的代碼。套用一張官方的圖來解釋。
爲什麼要這麼設計呢?主要還是處於管控和安全上的考慮。我們需要阻止開發者使用一些瀏覽器提供的,諸如跳轉頁面、操作 DOM、動態執行腳本的開放性接口。
小程序的生命週期
小程序的生命週期借鑑了Android的生命週期,如果你瞭解過Android的APP開發,那麼理解小程序的就會很簡單。
界面線程有四大狀態:
-
初始化狀態:初始化界面線程所需要的工作,包括工作機制,基本和我們開發者沒有關係,等初始化完畢就向“服務線程”發送初始化完畢信號,然後進入等待傳回初始化數據狀態。
-
首次渲染狀態:收到“服務線程”發來的初始化數據後(就是 json和js中的data數據),就開始渲染小程序界面,渲染完畢後,發送“首次渲染完畢信號”給服務線程,並將頁面展示給用戶。
-
持續渲染狀態:此時界面線程繼續一直等待“服務線程”通過this.setdata()函數發送來的界面數據,只要收到就重新局部渲染,也因此只要更新數據併發送信號,界面就自動更新。
-
結束狀態:結束渲染。
服務線程五大狀態:
- 初始化狀態:無需和其他模塊交流,跟小程序開發也沒多大關聯,此階段就是啓動服務線程所需的基本功能,比如信號發送模塊。系統的初始化工作完畢,就調用自定義的onload和onshow,
然後等待界面線程的“界面線程初始化完成”信號。
onload是隻會首次渲染的時候執行一次,onshow是每次界面切換都會執行,簡單理解,這就是唯一差別。
-
等待激活狀態:接收到“界面線程初始化完成”信號後,將初始化數據發送給“界面線程”,等待界面線程完成初次渲染。
-
激活狀態:收到界面線程發送來的“首次渲染完成”信號後,就進入激活狀態既程序的正常運行狀態,並調用自定義的onReady()函數。
此狀態下就可以通過 this.setData 函數發送界面數據給界面線程進行局部渲染,更新頁面。
- 後臺運行狀態:如果界面進入後臺,服務線程就進入後臺運行狀態,從目前的官方解讀來說,這個狀態挺奇怪的,和激活狀態是相同的,也可以通過setdata函數更新界面的。畢竟小程序的框架剛推出,應該後續會有很大不同吧。
小程序雙線程間的通信
把開發者的 JS 邏輯代碼放到單獨的線程去運行,但在 Webview 線程裏,開發者就沒法直接操作 DOM。那要怎麼去實現動態更改界面呢?
前面我們知道,邏輯層和渲染層的通信會由 Native (微信客戶端)做中轉,邏輯層發送網絡請求也經由 Native 轉發。這是不是意味着,我們可以把 DOM 的更新通過簡單的數據通信來實現呢?
Virtual DOM 相信大家都已有了解,大概是這麼個過程:用JS對象模擬DOM樹 -> 比較兩棵虛擬DOM樹的差異 -> 把差異應用到真正的DOM樹上。
在這裏我們可以用上,如圖:
-
在渲染層把 WXML 轉化成對應的 JS 對象。
-
在邏輯層發生數據變更的時候,通過宿主環境提供的 setData 方法把數據從邏輯層傳遞到 Native,再轉發到渲染層。
-
經過對比前後差異,把差異應用在原來的 DOM 樹上,更新界面。
我們通過把 WXML 轉化爲數據,通過 Native 進行轉發,來實現邏輯層和渲染層的交互和通信。而這樣完整的一套框架,基本上都是通過小程序的基礎庫來完成的。
小程序的基礎組件
native層就是小程序的框架,就像常用的react框架一樣,這個框架裏封裝了ui層組件和邏輯層組件,這些組件可以通過微信app提供的接口調用手機硬件信息
這些基礎組件庫是JavaScript編寫的,它可以被注入到渲染層和邏輯層運行。主要用於:
-
在渲染層,提供各類組件來組件頁面的元素
-
在邏輯層,提供各種API來處理各種元素。
-
處理數據綁定、組件系統、事件系統、通信系統等一系列框架邏輯
由於小程序的渲染層和邏輯層是兩個線程管理,兩個線程各自注入了基礎庫。小程序的基礎庫不會被打包在某個小程序的代碼包裏邊,它會被提前內置在微信客戶端。
如果需要學習更多的知識,請進入個人前端平臺: http://uyi2.com