使用微信小程序開發(fā)已經(jīng)很長時間了,對小程序開發(fā)已經(jīng)相當熟練了;但是作為一名對技術(shù)有追求的前端開發(fā),僅僅熟練掌握小程序的開發(fā)感覺還是不夠的,我們應(yīng)該更進一步的去理解其背后實現(xiàn)的原理以及對應(yīng)的考量,這可能會解釋我們在開發(fā)過程中遇到的一些疑惑,比如為啥小程序不能操作dom、小程序是web技術(shù)渲染還是native技術(shù)渲染等等,另一方面對于我們個人成長也是有幫組的。
首先聲明下,文章查看小程序開發(fā)者工具源碼的方法僅限學習使用。
本文將從以下幾個方面來說一下小程序的實現(xiàn)原理
如何查看小程序開發(fā)者工具源碼小程序架構(gòu)設(shè)計1、小程序渲染是在同一個線程嗎?雙線程機制2、小程序是web渲染嗎?界面渲染機制3、小程序是用web的html標簽渲染嗎?Exparser組件框架4、小程序可以操作dom嗎?數(shù)據(jù)驅(qū)動如何查看小程序開發(fā)者工具源碼
下面我們通過微信小程序開發(fā)者工具的源碼來說說小程序的底層實現(xiàn)原理。以開發(fā)者工具版本號
State v1.02.1904090
的源碼來窺探小程序的實現(xiàn)思路。如何查看微信源碼,對于mac用戶而言,查看微信小程序開發(fā)者工具的包內(nèi)容,然后進入Contents/Resources/App.nw/js/core/index.js
,注釋掉如下代碼就可以查看開發(fā)者工具渲染后的代碼。// 打開 inspect 窗口 if (nw.App.argv.indexOf('inspect') !== -1) { tools.openInspectWin() }
然后重啟小程序開發(fā)者工具,就出現(xiàn)如下左側(cè)頁面,點擊其中一個頁面就能看到view層的dom結(jié)構(gòu),如下圖右側(cè)。
小程序架構(gòu)設(shè)計
小程序的架構(gòu)設(shè)計與web技術(shù)還是有一定的差別,其吸取了web技術(shù)的一些優(yōu)勢,同時也摒棄web技術(shù)中體驗等不好的地方。下面通過問題的形式來說說小程序架構(gòu)中的一些設(shè)計點。
1、小程序渲染是在同一個線程嗎?雙線程機制
開發(fā)過小程序的都知道,小程序是雙線程設(shè)計,即視圖渲染與業(yè)務(wù)邏輯分別在運行在不同的線程中。這個設(shè)計主要是解決web技術(shù)中的一個痛點:
小程序為了更好體驗,將頁面的渲染線程和腳本線程分開設(shè)計在不同線程中執(zhí)行,具體實現(xiàn):
視圖view層在webview中渲染,一個頁面對應(yīng)一個webview業(yè)務(wù)邏輯Appservice層運行在同一個JSCore線程中,具體IOS是JAVAScriptCore,Android是X5 JSCore,開發(fā)者工具是webview中;這樣解決了長時間的腳本阻塞頁面渲染的情況,但是也帶來一些新的問題:
天生的延遲,線程間要通信業(yè)務(wù)邏輯層因為運行在JSCore中無法訪問DOM和BOM的api;開發(fā)者工具使用webview加載業(yè)務(wù)邏輯層的代碼,雖然依賴的環(huán)境有DOM和BOM api,為了保持一致;小程序?qū)λ械哪K進行了局部化處理使其不能訪問這些api。這樣雙線程通過native,開發(fā)者工具通過后臺websocket服務(wù)來進行二者消息中轉(zhuǎn)。具體可以參考官網(wǎng)圖:
2、小程序是web渲染嗎?界面渲染機制
頁面渲染的方式主要有三種:
純web渲染純native原生渲染Hybrid渲染,即web和native渲染結(jié)合因為小程序的宿主環(huán)境是微信,不太可能使用純native渲染,否則所有小程序需要跟微信一起編碼發(fā)版。采用純web渲染貌似是可行的,支持快速在線更新,通過加裝最新資源到本地即可渲染;但是純web渲染在一些有復雜交互的頁面上可能會面臨一些性能問題,這是因為在web技術(shù)中,UI渲染跟 JavaScript 的腳本執(zhí)行都在一個單線程中執(zhí)行,這就容易導致一些邏輯任務(wù)搶占UI渲染的資源。所以小程序采用Hybrid方式渲染,用官網(wǎng)的描述如下:
界面主要由成熟的 Web 技術(shù)渲染,輔之以大量的接口提供豐富的客戶端原生能力。同時,每個小程序頁面都是用不同的WebView去渲染,這樣可以提供更好的交互體驗,更貼近原生體驗,也避免了單個WebView的任務(wù)過于繁重。
既然采用Hybrid方式渲染,那么頁面的渲染可能會用到原生native來渲染,什么情況會用到原生渲染呢?
答案是使用到小程序提供的
map
、video
、canvas
、textarea
等組件,頁面中原生渲染的渲染原理可以參考官網(wǎng)原生組件。但是在小程序開發(fā)者工具中原生組件是使用html標簽來模擬實現(xiàn)的。具體可以看下一節(jié)的map組件渲染結(jié)果。3、小程序是用web的html標簽渲染嗎?Exparser組件框架
上面說到小程序主要由成熟的web技術(shù)渲染,能否直接使用html提供的標簽如div、table等組織頁面呢,答案不可以。主要考量:
管控與安全
:web技術(shù)可以通過腳本獲取修改頁面敏感內(nèi)容或者隨意跳轉(zhuǎn)其它頁面能力有限,會限制小程序的表現(xiàn)形式
標簽眾多,增加理解成本
所以,小程序不能直接使用html標簽渲染頁面,其提供了10多個內(nèi)置組件來收斂web標簽,并且提供一個JavaScript沙箱環(huán)境來避免js訪問任何瀏覽器api。
既然小程序不能直接使用html標簽來渲染頁面,那它提供的如
view
、cover-view
等內(nèi)置組件是否意味著最終都轉(zhuǎn)換為html提供的內(nèi)置標簽來渲染呢?答案當不是。我們來看如下代碼:上面代碼在開發(fā)者工具中最終渲染元素如下圖:
可以看出,小程序提供的組件并沒有最終轉(zhuǎn)換為為html對應(yīng)的標簽來渲染,而是使用自定義的元素來渲染。這些內(nèi)置組件都是由Exparser框架負責管理,它內(nèi)置在小程序基礎(chǔ)庫中,為小程序的各種組件提供基礎(chǔ)的支持。
Exparser框架基于Shadow DOM模型,模型上與WebComponents的ShadowDOM高度相似,具體可以參考官網(wǎng)組件系統(tǒng)。內(nèi)置組件創(chuàng)建方式如下:
4、小程序可以操作dom嗎?數(shù)據(jù)驅(qū)動
小程序為了管控與安全,提供一個JavaScript沙箱環(huán)境來運行JavaScript代碼,js代碼不能訪問任何瀏覽器相關(guān)的接口,那就意味著js是不能操作dom和bom的,否則可能報錯。小程序?qū)崿F(xiàn)沙箱環(huán)境呢?即通過將業(yè)務(wù)邏輯封裝到一個局部環(huán)境中,局部環(huán)境修改dom和bom的相關(guān)api指向。具體封裝如下:
define("pages/xx/xxx.js", function(require, module, exports, window,document,frames,self,location,navigator,localStorage,history,Caches,screen,alert,confirm,prompt,fetch,XMLHttpRequest,WebSocket,webkit,WeixinJSCore,Reporter,print,URL,DOMParser,upload,preview,build,showDecryptedInfo,syncMessage,checkProxy,showSystemInfo,openVendor,openToolsLog,showRequestInfo,help,showDebugInfoTable,closeDebug,showDebugInfo,__global,WeixinJSBridge){ 'use strict'; // your code here}
這里的define是小程序底層實現(xiàn)模塊化的方法之一,還有一個是require方法;通過define來定義一個模塊,require來引用一個define定義的模塊。從上面小程序?qū)I(yè)務(wù)模塊代碼的封裝可以看出:
define定義的模塊對傳遞了跟瀏覽器相關(guān)的接口同名的API,如window、document、localStroage等等require在引用模塊時只傳遞require、module、exports三個參數(shù),那么其他參數(shù)值就為undefined
,不能在業(yè)務(wù)代碼中訪問這些接口可以看看require定義的源碼:
在實際的微信環(huán)境,業(yè)務(wù)邏輯層運行在JSCore中,其沒有瀏覽器相關(guān)的信息,訪問dom無從談起;但是小程序開發(fā)者工具使用webview來運行業(yè)務(wù)邏輯代碼,它有dom相關(guān)接口;所以通過上面沙箱環(huán)境來統(tǒng)一使js無法操作dom。
業(yè)務(wù)代碼無法訪問dom,怎么實現(xiàn)頁面動態(tài)更新呢?
答案就是采用類vue這種MVVM框架的數(shù)據(jù)驅(qū)動思想,即讓視圖狀態(tài)和視圖綁定在一起,狀態(tài)變更時,視圖也能自動變更,這樣就不用直接操作dom。
視圖的動態(tài)更新具體是采用virtual dom技術(shù)實現(xiàn),virtual DOM相信大家都已有了解,大概是這么個過程:
下面以官網(wǎng)的一幅圖來說視圖動態(tài)更新的過程:
// wxml
1.《小程序設(shè)計開發(fā) 從微信小程序開發(fā)者工具源碼看小程序架構(gòu)設(shè)計實現(xiàn)原理》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識,僅代表作者本人觀點,與本網(wǎng)站無關(guān),侵刪請聯(lián)系頁腳下方聯(lián)系方式。
2.《小程序設(shè)計開發(fā) 從微信小程序開發(fā)者工具源碼看小程序架構(gòu)設(shè)計實現(xiàn)原理》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進行證實,對其原創(chuàng)性、真實性、完整性、及時性不作任何保證。
3.文章轉(zhuǎn)載時請保留本站內(nèi)容來源地址,http://f99ss.com/keji/347242.html