微信小程序是介于Native和web app之間的產(chǎn)物。它依托瀏覽器(webview)展示碌燕,同時(shí)可以調(diào)用原生能力(如獲取通信錄咒劲,拍照等等),同一份代碼可運(yùn)行在Android饲齐,iOS和微信調(diào)試開發(fā)工具內(nèi)(跨平臺(tái)能力)钉凌。
與RN的跨平臺(tái)不同,小程序大部分UI組件并不是原生渲染捂人,還是類似web app用瀏覽器渲染御雕。只有少量組件是Native實(shí)現(xiàn)(Native組件層在WebView層之上): <canvas/> <video/> <map/> <textarea/>
。
那么滥搭,小程序和web app有什么區(qū)別呢酸纲??jī)H僅只是能夠通過JsBridage調(diào)用Native能力的區(qū)別嗎?
答案:No论熙!No福青!No摄狱!
相信每位學(xué)習(xí)小程序的同學(xué)都看過Page生命周期這節(jié)脓诡,圖中有『View Thread』和『AppService Thread』兩個(gè)線程圖。為什么有兩個(gè)線程媒役?每個(gè)線程處理什么祝谚?和webview的關(guān)系如何?
為了更好的了解的真相酣衷,讓我們先溫習(xí)下瀏覽器如何運(yùn)行交惯,如何展示UI。
瀏覽器運(yùn)行環(huán)境
首先,瀏覽器的主要組件有:
- 用戶界面(User Interface) - 地址欄席爽、前進(jìn)/后退按鈕意荤、書簽菜單等(除了瀏覽器主窗口外,其他顯示的各個(gè)部分都屬于用戶界面)只锻。
- 瀏覽器引擎(Browser engine) - 在用戶界面和呈現(xiàn)引擎之間傳送指令玖像。
- 呈現(xiàn)引擎(Rendering engine)
important
- 負(fù)責(zé)顯示請(qǐng)求的內(nèi)容(如果請(qǐng)求的內(nèi)容是 HTML,它就負(fù)責(zé)解析 HTML 和 CSS 內(nèi)容齐饮,并將解析后的內(nèi)容顯示在屏幕上)捐寥。 - JavaScript 解釋器(JavaScript Interpreter)
important
- 用于解析和執(zhí)行 JavaScript 代碼。 - 網(wǎng)絡(luò)(Networking) - 用于網(wǎng)絡(luò)調(diào)用祖驱,比如 HTTP 請(qǐng)求握恳。其接口與平臺(tái)無關(guān),并為所有平臺(tái)提供底層實(shí)現(xiàn)捺僻。
- 數(shù)據(jù)存儲(chǔ)(Data Persistence)乡洼。這是持久層。瀏覽器需要在硬盤上保存各種數(shù)據(jù)匕坯,例如 Cookie就珠。新的 HTML 規(guī)范 (HTML5) 定義了“網(wǎng)絡(luò)數(shù)據(jù)庫(kù)”,這是一個(gè)完整(但是輕便)的瀏覽器內(nèi)數(shù)據(jù)庫(kù)醒颖。
- 用戶界面后端(UI Backend) - 用于繪制基本的窗口小部件妻怎,比如組合框和窗口。其公開了與平臺(tái)無關(guān)的通用接口泞歉,而在底層使用操作系統(tǒng)的用戶界面方法逼侦。
參考下圖:
一般來說,瀏覽器運(yùn)行在一個(gè)進(jìn)程中(但是chrome比較特殊腰耙,每個(gè)標(biāo)簽頁(yè)都是一個(gè)獨(dú)立進(jìn)程)榛丢。同時(shí),瀏覽器是多線程的挺庞,比較重要的線程有:
- 呈現(xiàn)引擎(又稱為渲染引擎):運(yùn)行在UI線程中晰赞。
- JavaScript 解釋器(又稱為JS解析引擎):運(yùn)行在JS引擎線程中。
注意:UI 渲染線程與 JavaScript 引擎線程為互斥的關(guān)系选侨,當(dāng) JavaScript 引擎線程執(zhí)行時(shí) UI 渲染線程會(huì)被掛起掖鱼,UI 更新會(huì)被保存在一個(gè)隊(duì)列中等到 JavaScript 引擎線程空閑時(shí)立即被執(zhí)行。
小程序運(yùn)行環(huán)境
小程序運(yùn)行時(shí)會(huì)有兩個(gè)線程:『View Thread』和『AppService Thread』援制,相互隔離戏挡,通過橋接協(xié)議WeixinJsBridage進(jìn)行通信(包括 setData 調(diào)用、canvas指令和各種DOM事件)
下述表格展示了兩個(gè)線程的區(qū)別:
線程名稱 | 所屬模塊 | 運(yùn)行代碼 | 原理 | 備注 |
---|---|---|---|---|
View | 視圖層(可能有多個(gè)) | WXML/WXSS | webview渲染 | wxml編譯器把wxml文件轉(zhuǎn)為js(構(gòu)建virtual dom); wxss編譯器把wxss文件轉(zhuǎn)化為js |
AppService | 邏輯層(一個(gè)) | JS | JavascriptCore運(yùn)行 | 無法訪問 window/document對(duì)象 |
兩個(gè)線程直接如何進(jìn)行數(shù)據(jù)傳遞晨仑?可參考微信官方說明:
通過兩邊提供的 evaluateJavascript 所實(shí)現(xiàn)褐墅。即用戶傳輸?shù)臄?shù)據(jù)拆檬,需要將其轉(zhuǎn)換為字符串形式傳遞,同時(shí)把轉(zhuǎn)換后的數(shù)據(jù)內(nèi)容拼接成一份 JS 腳本妥凳,再通過執(zhí)行 JS 腳本的形式傳遞到兩邊獨(dú)立環(huán)境
也就是說竟贯,兩個(gè)『模塊/線程』是通過系統(tǒng)層的JSBridage來通信的,邏輯層把數(shù)據(jù)變化通知到視圖層逝钥,觸發(fā)視圖層頁(yè)面更新澄耍,視圖層把觸發(fā)的事件通知到邏輯層進(jìn)行業(yè)務(wù)處理∩卧担可參考下圖:
所以可以得出如下結(jié)論:
- 小程序js代碼無法操作DOM對(duì)象齐莲,也無法直接操作wxml上的容器或組件(js代碼和webview沒有運(yùn)行在同一個(gè)線程中)
- 如果需要在View Thread中運(yùn)行自定義js代碼,可以使用
wxs
(微信開發(fā)的腳本語言)磷箕,它和View同一個(gè)線程选酗。
js引擎
平臺(tái) | 渲染 | js運(yùn)行環(huán)境 |
---|---|---|
iOS | WKWebView渲染(環(huán)境有 iOS8、iOS9岳枷、iOS10) | JavaScriptCore |
Android | X5 基于 Mobile Chrome 37 內(nèi)核來渲染 | X5 JSCore來解析 |
開發(fā)工具 | Chrome Webview 渲染 | nwjs 中 |
小結(jié)
雖然目前小程序使用 webview 渲染芒填,但是不意味著它以后也一直使用webview渲染。作為開發(fā)者空繁,只能依賴小程序提供的環(huán)境殿衰。而這個(gè)環(huán)境再下層如何處理,并不受開發(fā)者控制盛泡,這意味小程序未來很可能全面采用原生渲染闷祥,類似RN或Weex,畢竟傲诵,原生的UI體驗(yàn)更好凯砍。
參考文章