android工程師學習微信小程序筆記⑪ 小程序底層框架

雙線程模型

管控與安全

要徹底解決這個問題,我們必須提供一個沙箱環境來運行開發者的JavaScript 代碼。這個沙箱環境不能有任何瀏覽器相關接口,只提供純JavaScript 的解釋執行環境,那麼像HTML5中的ServiceWorker、WebWorker
特性就符合這樣的條件,這兩者都是啓用另一線程來執行 JavaScript。但是考慮到小程序是一個多 WebView 的架構,每一個小程序頁面都是不同的WebView 渲染後顯示的,在這個架構下我們不好去用某個WebView中的ServiceWorker去管理所有的小程序頁面。

得益於客戶端系統有JavaScript 的解釋引擎(在iOS下是用內置的 JavaScriptCore框架,在安卓則是用騰訊x5內核提供的JsCore環境),我們可以創建一個單獨的線程去執行 JavaScript,在這個環境下執行的都是有關小程序業務邏輯的代碼,也就是我們前面一直提到的邏輯層。而界面渲染相關的任務全都在WebView線程裏執行,通過邏輯層代碼去控制渲染哪些界面,那麼這一層當然就是所謂的渲染層。這就是小程序雙線程模型的由來。

天生的延時

既然小程序是基於雙線程模型,那就意味着任何數據傳遞都是線程間的通信,也就是都會有一定的延時。

這不像傳統Web那樣,當界面需要更新時,通過調用更新接口UI就會同步地渲染出來。

在小程序架構裏,這一切都會變成異步。

異步會使得各部分的運行時序變得複雜一些。

比如在渲染首屏的時候,邏輯層與渲染層會同時開始初始化工作,但是渲染層需要有邏輯層的數據才能把界面渲染出來,如果渲染層初始化工作較快完成,就要等邏輯層的指令才能進行下一步工作。

因此邏輯層與渲染層需要有一定的機制保證時序正確,這些工作在小程序框架裏會處理好,開發者只需要理解生命週期,以及控制合適的時機更新UI即可。

除了邏輯層與渲染層之間的通信有延時,各層與客戶端原生交互同樣是有延時的。以邏輯層爲例,開發者的代碼是跑在邏輯層這個線程之上,而客戶端原生是跑在微信主線程(安卓上是線程)之上,所以註冊給邏輯層有關客戶端能力的接口,實際上也是跟微信主線程之間的通信,同樣意味着有延時。這也是我們看到大部分提供的接口都是異步的原因。

組件系統

小程序裏面設計了一套 組件框架 —— Exparser。

Exparser框架

Exparser是微信小程序的組件組織框架,內置在小程序基礎庫中,爲小程序的各種組件提供基礎的支持。小程序內的所有組件,包括內置組件和自定義組件,都由Exparser組織管理。

Exparser的組件模型與WebComponents標準中的ShadowDOM高度相似。

Exparser會維護整個頁面的節點樹相關信息,包括節點的屬性、事件綁定等,相當於一個簡化版的Shadow DOM實現。Exparser的主要特點包括以下幾點:

  • 基於Shadow DOM模型:模型上與WebComponents的ShadowDOM高度相似,但不依賴瀏覽器的原生支持,也沒有其他依賴庫;實現時,還針對性地增加了其他API以支持小程序組件編程。
  • 可在純JS環境中運行:這意味着邏輯層也具有一定的組件樹組織能力。
  • 高效輕量:性能表現好,在組件實例極多的環境下表現尤其優異,同時代碼尺寸也較小。

小程序中,所有節點樹相關的操作都依賴於Exparser,包括WXML到頁面最終節點樹的構建、createSelectorQuery調用和自定義組件特性等。

組件的節點樹稱爲“ShadowTree”,即組件內部的實現;最終拼接成的頁面節點樹被稱爲“Composed Tree”,即將頁面所有組件節點樹合成之後的樹。在進行了這樣的組件分離之後,整個頁面節點樹實質上被拆分成了若干個ShadowTree(頁面的body實質上也是一個組件,因而也是一個ShadowTree)。

運行原理

在使用自定義組件的小程序頁面中,Exparser將接管所有的自定義組件註冊與實例化。

從外部接口上看,小程序基礎庫提供有Page和Component兩個構造器。

以Component爲例,在小程序啓動時,構造器會將開發者設置的properties、data、methods等定義段,寫入Exparser的組件註冊表中。這個組件在被其它組件引用時,就可以根據這些註冊信息來創建自定義組件的實例。Page構造器的大體運行流程與之相仿,只是參數形式不一樣。這樣每個頁面就有一個與之對應的組件,稱爲“頁面根組件”。(這個過程跟Java類和對象的概念非常相像)

在初始化頁面時,Exparser會創建出頁面根組件的一個實例,用到的其他組件也會響應創建組件實例(這是一個遞歸的過程)。組件創建的過程大致有以下幾個要點:

  1. 根據組件註冊信息,從組件原型上創建出組件節點的JS對象,即組件的this
  2. 將組件註冊信息中的data 複製一份,作爲組件數據,即this.data
  3. 將這份數據結合組件WXML,據此創建出Shadow Tree,由於Shadow Tree中可能引用有其他組件,因而這會遞歸觸發其他組件創建過程;
  4. 將ShadowTree拼接到Composed Tree上,並生成一些緩存數據用於優化組件更新性能;
  5. 觸發組件的created生命週期函數;
  6. 如果不是頁面根組件,需要根據組件節點上的屬性定義,來設置組件的屬性值;
  7. 當組件實例被展示在頁面上時,觸發組件的attached 生命週期函數,如果Shadw Tree中有其他組件,也逐個觸發它們的生命週期函數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章