前言
了解微信小程序原理,感覺可以幫助自己更好理解為什么有些問題是這樣那樣的,整理了下,以前發(fā)現(xiàn)的一些問題也更能理解了
基本架構(gòu)
小程序的基本架構(gòu)由View視圖層、APPServices邏輯層組成,兩者之間是相對(duì)獨(dú)立,它們之間是通過微信的JSBridge來進(jìn)行通信和協(xié)作的。
渲染層的界面使用了WebView 進(jìn)行渲染;邏輯層采用JsCore線程運(yùn)行JS腳本。一個(gè)小程序存在多個(gè)界面,所以渲染層存在多個(gè)WebView線程,這兩個(gè)線程的通信會(huì)經(jīng)由微信客戶端(下文中也會(huì)采用Native來代指微信客戶端)做中轉(zhuǎn),邏輯層發(fā)送網(wǎng)絡(luò)請求也經(jīng)由Native轉(zhuǎn)發(fā)。


運(yùn)行機(jī)制:
小程序啟動(dòng)可以分為兩種情況,一種是冷啟動(dòng),一種是熱啟動(dòng)。
- 冷啟動(dòng):如果用戶首次打開,或小程序銷毀后被用戶再次打開,此時(shí)小程序需要重新加載啟動(dòng),即冷啟動(dòng)。
- 熱啟動(dòng):如果用戶已經(jīng)打開過某小程序,然后在一定時(shí)間內(nèi)再次打開該小程序,此時(shí)小程序并未被銷毀,只是從后臺(tái)狀態(tài)進(jìn)入前臺(tái)狀態(tài),這個(gè)過程就是熱啟動(dòng)。
小程序銷毀時(shí)機(jī)
通常,只有當(dāng)小程序進(jìn)入后臺(tái)一定時(shí)間,或者系統(tǒng)資源占用過高,才會(huì)被銷毀。具體而言包括以下幾種情形:
- 當(dāng)小程序進(jìn)入后臺(tái),可以維持一小段時(shí)間的運(yùn)行狀態(tài),如果這段時(shí)間內(nèi)都未進(jìn)入前臺(tái),小程序會(huì)被銷毀。
- 當(dāng)小程序占用系統(tǒng)資源過高,可能會(huì)被系統(tǒng)銷毀或被微信客戶端主動(dòng)回收。
- 在 iOS 上,當(dāng)微信客戶端在一定時(shí)間間隔內(nèi)連續(xù)收到系統(tǒng)內(nèi)存告警時(shí),會(huì)根據(jù)一定的策略,主動(dòng)銷毀小程序,并提示用戶 「運(yùn)行內(nèi)存不足,請重新打開該小程序」。具體策略會(huì)持續(xù)進(jìn)行調(diào)整優(yōu)化。
- 建議小程序在必要時(shí)使用 wx.onMemoryWarning 監(jiān)聽內(nèi)存告警事件,進(jìn)行必要的內(nèi)存清理。
更新機(jī)制
未啟動(dòng)時(shí)更新
開發(fā)者在管理后臺(tái)發(fā)布新版本的小程序之后,如果某個(gè)用戶本地有小程序的歷史版本,此時(shí)打開的可能還是舊版本。微信客戶端會(huì)有若干個(gè)時(shí)機(jī)去檢查本地緩存的小程序有沒有更新版本,如果有則會(huì)靜默更新到新版本??偟膩碚f,開發(fā)者在后臺(tái)發(fā)布新版本之后,無法立刻影響到所有現(xiàn)網(wǎng)用戶,但最差情況下,也在發(fā)布之后 24 小時(shí)之內(nèi)下發(fā)新版本信息到用戶。用戶下次打開時(shí)會(huì)先更新最新版本再打開。
啟動(dòng)時(shí)更新
小程序每次冷啟動(dòng)時(shí),都會(huì)檢查是否有更新版本,如果發(fā)現(xiàn)有新版本,將會(huì)異步下載新版本的代碼包,并同時(shí)用客戶端本地的包進(jìn)行啟動(dòng),即新版本的小程序需要等下一次冷啟動(dòng)才會(huì)應(yīng)用上。
如果需要馬上應(yīng)用最新版本,可以使用 wx.getUpdateManager API 進(jìn)行處理。
View視圖層
由WXML、WXSS兩部分組成
AppServices邏輯層
1、App( ) 小程序的入口;
2、Page( ) 頁面的入口
3、提供豐富的 API,如微信用戶數(shù)據(jù),掃一掃,支付等微信特有能力。
4、每個(gè)頁面有獨(dú)立的作用域,并提供模塊化能力。
5、數(shù)據(jù)綁定、事件分發(fā)、生命周期管理、路由管理運(yùn)行環(huán)境
邏輯層的運(yùn)行環(huán)境
IOS - JSCore
Android - X5 JS解析器
DevTool - nwjs Chrome 內(nèi)核
setData機(jī)制
小程序的視圖層目前使用 WebView 作為渲染載體,而邏輯層是由獨(dú)立的 JavascriptCore 作為運(yùn)行環(huán)境。在架構(gòu)上,WebView 和 JavascriptCore 都是獨(dú)立的模塊,并不具備數(shù)據(jù)直接共享的通道。當(dāng)前,視圖層和邏輯層的數(shù)據(jù)傳輸,實(shí)際上通過兩邊提供的 evaluateJavascript 所實(shí)現(xiàn)。即用戶傳輸?shù)臄?shù)據(jù),需要將其轉(zhuǎn)換為字符串形式傳遞,同時(shí)把轉(zhuǎn)換后的數(shù)據(jù)內(nèi)容拼接成一份 JS 腳本,再通過執(zhí)行 JS 腳本的形式傳遞到兩邊獨(dú)立環(huán)境。
而 evaluateJavascript 的執(zhí)行會(huì)受很多方面的影響,數(shù)據(jù)到達(dá)視圖層并不是實(shí)時(shí)的
簡單理解的話,如用戶在視圖層觸發(fā)一些交互,底層代碼的邏輯是:
View視圖層->JSBridge->APPServices邏輯層->JSBridge->View視圖層
這種復(fù)雜的交互邏輯,在一些強(qiáng)交互場景下就會(huì)顯得卡頓,所以原生組件出現(xiàn)。
原生組件的邏輯是
原生組件->APPServices邏輯層->原生組件
因?yàn)樵M件本身是有客戶端控制(可以理解為JSBridge),所以簡化了代碼交互的邏輯。
由于原生組件脫離在 WebView 渲染流程外,所以在使用原生組件時(shí),跟小程序普通組件存在一些差異:
- 原生組件的層級(jí)是最高的,所以頁面中的其他組件無論設(shè)置
z-index為多少,都無法蓋在原生組件上。- 后插入的原生組件可以覆蓋之前的原生組件。
- 原生組件還無法在 中使用。
- 基礎(chǔ)庫 2.4.4 以下版本,原生組件不支持在 scroll-view、swiper、movable-view 中使用。
- 部分CSS樣式無法應(yīng)用于原生組件,例如:
- 無法對(duì)原生組件設(shè)置 CSS 動(dòng)畫
- 無法定義原生組件為
position: fixed - 不能在父級(jí)節(jié)點(diǎn)使用
overflow: hidden來裁剪原生組件的顯示區(qū)域
- 原生組件的事件監(jiān)聽不能使用
bind:eventname的寫法,只支持bindeventname。原生組件也不支持 catch 和 capture 的事件綁定方式。 - 原生組件會(huì)遮擋 vConsole 彈出的調(diào)試面板。 在工具上,原生組件是用web組件模擬的,因此很多情況并不能很好的還原真機(jī)的表現(xiàn),建議開發(fā)者在使用到原生組件時(shí)盡量在真機(jī)上進(jìn)行調(diào)試。
參考