首頁 >微信小程式 >小程式開發 >淺析小程式運作機制

淺析小程式運作機制

藏色散人
藏色散人轉載
2020-05-21 13:46:552391瀏覽

寫作背景

接觸小程式有一段時間了,總得來說小程式開發門檻比較低,但其中基本的運作機制和原理還是要懂的。 “例如我在面試的時候問到一個關於小程序的問題,問小程式有window對象嗎?他說有吧”,但其實是沒有的。感覺他並沒有了解小程式底層的一些東西,歸根究底來說應該只能算會使用這個工具,但卻不明白其中的道理。

小程式與一般網頁開發是有很大差別的,這就要從它的技術架構底層去剖析了。還有例如習慣Vue,react開發的開發者會吐槽小程式新建頁面的繁瑣,page必須由多個檔案組成、元件化支援不完善、每次變更data 裡的資料都得setData、沒有像Vue方便的watch監聽、不能操作Dom,對於複雜性場景不太好,之前不支援npm,不支援sass,less預編譯處理語言。

“有的人說小程式就像被閹割的Vue”,哈哈當然了,他們從設計的出發點就不同,咱也得理解小程式設計的初衷,透過它的使用場景,它為什麼採用這種技術架構,這種技術架構有什麼好處,相信在你了解這些之後,就會理解了。下面我會從以下幾個角度去分析小程式的運作機制和它的整體技術架構。

了解小程式的由來

在小程式沒有出來之前,最初微信WebView逐漸成為行動web重要入口,微信發布了一整套網頁開發工具包,稱之為JS-SDK,為所有的Web 開發者打開了一扇全新的窗戶,讓所有開發者都可以使用到微信的原生能力,去完成一些之前做不到或難以做到的事情。

但JS-SDK 的模式並沒有解決使用行動網頁遇到的體驗不良的問題,例如受限於裝置效能和網路速度,會出現白螢幕的可能。因此又設計了一個增強版JS-SDK,也就是“微信 Web 資源離線存儲”,但在復雜的頁面上依然會出現白屏的問題,原因表現在頁面切換的生硬和點擊的遲滯感。這時候需要一個 JS-SDK 所處理不了的,使用戶體驗更好的一個系統,小程式應運而生。

快速的載入

更強大的能力

原生的體驗

易用且安全的微信資料開放

#有效率和簡單的開發

小程式與普通網頁開發的區別

小程式的開發同普通的網頁開發相比有很大的相似性,小程式的主要開發語言也是JavaScript,但二者還是有些差異的。

普通網頁開發可以使用各種瀏覽器提供的DOM API,進行DOM 操作,小程式的邏輯層和渲染層是分開的,邏輯層運行在JSCore 中,並沒有一個完整瀏覽器對象,因而缺少相關的DOM API和BOM API。

普通網頁開發渲染執行緒和腳本執行緒是互斥的,這也是為什麼長時間的腳本運行可能會導致頁面失去回應,而在小程式中,二者是分開的,分別運行在不同的線程中。

網頁開發者在開發網頁的時候,只需要使用到瀏覽器,並且搭配上一些輔助工具或編輯器即可。小程式的開發則有所不同,需要經過申請小程式帳號、安裝小程式開發者工具、設定專案等等流程方可完成。

小程式的執行環境

小程式架構

一、技術選型

一般來說,渲染介面的技術有三種:

用純客戶端原生技術來渲染

用純Web 技術來渲染

用客戶端原生技術與Web 技術結合的混合技術(簡稱Hybrid 技術)來渲染

透過以下幾個面向分析,小程式採用哪種技術方案

開發門檻:Web 門檻低,Native 也有像RN 這樣的框架支援

體驗:Native 體驗比Web 好太多,Hybrid 在某種程度上比Web 接近原生體驗

版本更新:Web 支援線上更新,Native 則需要打包到微信一起審核發布

管控和安全:Web 可跳轉或是改變頁面內容,存在一些不可控因素和安全風險

由於小程式的宿主環境是微信,如果用純客戶端原生技術來寫小程序,那麼小程式碼每次都需要與微信程式碼一起發版,這種方式肯定是不行的。

所以需要像web技術一樣,有一份隨時可更新的資源包放在雲端,透過下載到本地,動態執行後即可渲染出介面。如果用純web技術來渲染小程序,在一些複雜的交互上可能會面臨一些效能問題,這是因為在web技術中,UI渲染跟JavaScript的腳本執行都在一個單線程中執行,這就容易導致有些邏輯任務搶佔UI渲染的資源。

所以最終採用了兩者結合起來的Hybrid 技術來渲染小程序,可以用一種近似web的方式來開發,並且可以實現在線更新代碼,同時引入組件也有以下好處:

擴充 Web 的能力。例如像輸入框元件(input, textarea)有更好地控制鍵盤的能力

體驗更好,同時也減輕WebView 的渲染工作

繞過setData、資料通訊和重渲染流程,讓渲染效能更好

用客戶端原生渲染內建一些複雜元件,可以提供更好的效能

二、雙執行緒模型

#小程式的渲染層和邏輯層分別由2 個執行緒管理:視圖層的介面使用了WebView 進行渲染,邏輯層採用JsCore 執行緒執行JS腳本。

那麼為什麼要這樣設計呢,前面也提到了管控和安全,為了解決這些問題,我們需要阻止開發者使用一些,例如瀏覽器的window對象,跳轉頁面、操作DOM、動態執行腳本的開放性介面。

我們可以使用客戶端系統的 JavaScript 引擎,iOS 下的 JavaScriptCore 框架,安卓下騰訊 x5 核心提供的 JsCore 環境。

這個沙箱環境只提供純 JavaScript 的解釋執行環境,沒有任何瀏覽器相關介面。

這就是小程式雙執行緒模型的由來:

邏輯層:建立一個單獨的執行緒去執行JavaScript,這裡執行的都是有關小程式業務邏輯的程式碼,負責邏輯處理、資料請求、介面呼叫等

視圖層:介面渲染相關的任務全都在WebView 執行緒執行,透過邏輯層程式碼去控制渲染哪些介面。一個小程式存在多個介面,所以視圖層存在多個WebView 執行緒

JSBridge 起到架起上層開發與Native(系統層)的橋樑,使得小程式可透過API使用原生的功能,且部分元件為原生元件實現,從而有良好體驗

三、雙執行緒通訊

把開發者的JS 邏輯程式碼放到單獨的執行緒去運行,但在Webview 執行緒裡,開發者就沒辦法直接操作DOM。

那要怎麼去實作動態變更介面呢?

如上圖所示,邏輯層和試圖層的通訊會由 Native (微信客戶端)做中轉,邏輯層發送網路請求也經由 Native 轉送。

這也就是說,我們可以把 DOM 的更新透過簡單的資料通訊來實現。

Virtual DOM 相信大家都已有了解,大概是這麼過程:用JS 物件模擬DOM 樹-> 比較兩棵虛擬DOM 樹的差異-> 把差異應用到真正的DOM 樹上。

如圖所示:

在渲染層把 WXML 轉換成對應的 JS 物件。

在邏輯層發生資料變更的時候,透過宿主環境提供的 setData 方法把資料從邏輯層傳遞到 Native,然後再轉送到渲染層。

經過對比前後差異,把差異應用在原來的 DOM 樹上,更新介面。

我們透過把 WXML 轉換為數據,透過 Native 進行轉發,來實現邏輯層和渲染層的互動和通訊。

而這樣一個完整的框架,離不開小程式的基礎函式庫。

四、小程式的基礎函式庫

小程式的基礎函式庫可以被注入到視圖層和邏輯層運行,主要用於以下幾個方面:

在視圖層,提供各類元件來組成介面的元素

在邏輯層,提供各類API 來處理各種邏輯

處理資料綁定、元件系統、事件系統、通訊系統等一系列框架邏輯

由於小程式的渲染層和邏輯層是兩個執行緒管理,兩個執行緒各自註入了基礎函式庫。

小程式的基礎函式庫不會被打包在某個小程式的程式碼包裡邊,它會被事先內建在微信客戶端。

這樣可以:

降低業務小程式的程式碼包大小

可以單獨修復基礎庫中的Bug,而無需修改到業務小程式的程式碼包

五、Exparser 框架

Exparser是微信小程式的元件組織框架,內建在小程式基礎庫中,為小程式的各種元件提供基礎的支援。小程式內的所有元件,包括內建元件和自訂元件,都由Exparser組織管理。

Exparser的主要特點包括以下幾點:

基於Shadow DOM模型:模型上與WebComponents的ShadowDOM高度相似,但不依賴瀏覽器的原生支持,也沒有其他依賴函式庫;實作時,也針對性地增加了其他API以支援小程式元件程式設計。

可在純JS環境中運作:這表示邏輯層也具有一定的元件樹組織能力。

高效輕量:效能表現好,在元件實例極多的環境下表現尤其優異,同時程式碼尺寸也較小。

小程式中,所有節點樹相關的操作都依賴Exparser,包括WXML到頁面最終節點樹的建置、createSelectorQuery呼叫和自訂元件特性等。

內建元件

基於Exparser框架,小程式內建了一套元件,提供了視圖容器類別、表單類別、導航類別、媒體類別、開放類別等幾十種組件。有了這麼豐富的組件,再配合WXSS,可以搭建任何效果的介面。在功能層面上,也滿足絕大部分需求。

六、運行機制

小程式啟動會有兩種情況,一種是「冷啟動」,一種是「熱啟動」。假如用戶已經打開過某小程序,然後在一定時間內再次打開該小程序,此時無需重新啟動,只需將後台狀態的小程序切換到前台,這個過程就是熱啟動;冷啟動指的是用戶首次開啟或小程式被微信主動銷毀後再次開啟的情況,此時小程式需要重新載入啟動。

小程式沒有重新啟動的概念

當小程式進入後台,客戶端會維持一段時間的運作狀態,超過一定時間後(目前是5分鐘)會被微信主動銷毀

當短時間內(5s)連續收到兩次以上收到系統記憶體告警,會進行小程式的銷毀

七、更新機制

小程式冷啟動時如果發現有新版本,將會異步下載新版本的程式碼包,並同時用客戶端本地的包進行啟動,即新版本的小程式需要等下一次冷啟動才會應用上。如果需要馬上套用最新版本,可以使用 wx.getUpdateManager API 來處理。

八、效能最佳化

主要的最佳化策略可以歸納為三點:

精簡程式碼,降低WXML結構和JS程式碼的複雜性;

合理使用setData調用,減少setData次數和資料量;

必要時使用分包優化。

1、setData 工作原理

小程式的視圖層目前使用 WebView 作為渲染載體,而邏輯層則是由獨立的 JavascriptCore 作為運作環境。在架構上,WebView 和 JavascriptCore 都是獨立的模組,並不具備資料直接共享的通道。目前,視圖層和邏輯層的資料傳輸,實際上透過兩邊提供的 evaluateJavascript 所實現。也就是使用者傳輸的數據,需要將其轉換為字串形式傳遞,同時把轉換後的數據內容拼接成一份 JS 腳本,再透過執行 JS 腳本的形式傳遞到兩邊獨立環境。

而 evaluateJavascript 的執行會受很多方面的影響,資料到達視圖層並不是即時的。

2、常見的setData 操作錯誤

頻繁的去setData在我們分析過的一些案例裡,部分小程式會非常頻繁(毫秒級)的去setData,其導致了兩個後果:Android下用戶在滑動時會感覺到卡頓,操作反饋延遲嚴重,因為JS 線程一直在編譯執行渲染,未能及時將用戶操作事件傳遞到邏輯層,邏輯層亦無法及時將操作處理結果及時傳遞到視圖層;渲染有出現延遲,由於WebView 的JS 執行緒一直處於忙碌狀態,邏輯層到頁面層的通訊耗時上升,視圖層收到的資料訊息時距離發出時間已經過了幾百毫秒,渲染的結果並不實時;

每次setData 都傳遞大量新資料由setData的底層實作可知,我們的資料傳輸實際上是一次evaluateJavascript

#腳本過程,當資料量過大時會增加腳本的編譯執行時間,佔用WebView JS 線程, 後台態頁面進行setData當頁面進入後台態(用戶不可見),不應該繼續去進行setData,後台態頁面的渲染用戶是無法感受的,另外後台態頁面去setData也會搶佔前台頁面的執行。

總結

大致上從以上幾個角度分析了小程式的底層架構,從小程式的由來、到雙執行緒的出現、設計、通訊、到基礎函式庫、Exparser 框架、再到運作機制、效能最佳化等等,都是一個相關而又相互影響的選擇。關於小程式的底層框架設計,應該還有很多,每個框架的誕生都有其意義,我們身為開發者能做的不只是會使用這個工具,還應該理解它的設計模式。這樣才不會被工具左右,才能走的更遠!

以上是淺析小程式運作機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除