為了讓大家更好的理解小程序的一些限制和做一些優(yōu)化,下面從小程序的基礎(chǔ)架構(gòu)講起,如有不對的地方,望指正,請輕噴 :smile:
首先,我們看看下圖,小程序的架構(gòu)如下:

我們可以看到,一個頁面使用一個 WebView 線程進(jìn)行渲染。 如果于頁面棧有 10 層,則會開啟 10 個 WebView 線程,占多一點(diǎn)內(nèi)存,所以對頁面棧進(jìn)行了限制。
那如果在10層頁面棧的限制內(nèi),由于頁面的內(nèi)容過于復(fù)雜,內(nèi)存爆了怎么辦? 小程序內(nèi)部有一個回收機(jī)制,如果內(nèi)存緊張時,會回收掉一部分 WebView 。
很多人可能會覺得, 10 層頁面棧基本已經(jīng)夠用了,無須關(guān)注這方面的限制了。
但是如果出現(xiàn)循環(huán)引用的話,用戶反復(fù)點(diǎn)擊,則很容易出現(xiàn)爆棧的情況。 如下圖:

所以,在開發(fā)之前,提前梳理好頁面之間的跳轉(zhuǎn),合理使用 navigator ,redirectTo, navigateBack …… 是非常重要的。
當(dāng)然,作為一個程序員,我并不想在跳轉(zhuǎn)的時候去時時刻刻的關(guān)注我有沒有正確引用,有沒有超出10層頁面棧。 完全可以對小程序的跳轉(zhuǎn)做一個封裝。
因為只有 wx.navigateTo 才會使頁面棧 + 1 ,那我們只要對這個方法做一層兜底處理即可。 如下代碼:
const PAGE_LIMIT = 10
const pages = getCurrentPages()
if(pages.length >= PAGE_LIMIT) {
// 使用 wx.redirectTo 方法
}
|
這樣就可以隨心所欲的跳來跳去了。
小程序的邏輯層是在 JsCore 中運(yùn)行的。限制如下:
還是從一張圖說起:

不同于頁面的渲染,所有的腳本邏輯都是跑在同一個 JsCode 線程里面,類似于路由中改變 Hash 值。 因此也會引起下面一些常見的坑
像 canvas , video ,input ,map ,picker …… 組件,官方直接使用原生組件,渲染方式如下圖:

從上圖很容易就可以看出,Navtive 組件的層級是最高的,那么僅僅去改變 z-index 也無法讓其他組件覆蓋原生組件。還好,官方給出了一個解決方案:
如果以往在移動端, PC 的接口會使用 Cookie 進(jìn)行一些處理,那在小程序中使用該接口就比較尷尬了。
因此,我們可以在小程序中也模擬出 Cookie ,如下圖:

在 Storage 中隔離一個字段,用來做 Cookie ,下面用了一個小技巧,把 Cookie 的內(nèi)容存放于內(nèi)存中,而非每次都從 storage 中讀取。
let cookie = (function(){
return wx.getStorageSync('cookies');
}())
const Cooke = {
getCookie(){}, //從內(nèi)存中獲取cookie
setCookie(){}, // 設(shè)置cookie
setCookieInHeader(){}, //根據(jù)response的Header設(shè)置cookie
removeCookie() {}, //刪除cookie
isExpired() {} //判斷是否過期
}
|
然后,我們在每次 Request 成功后,解析 Header 中 SET-COOKIE 屬性設(shè)置 Cookie ,在每一次請求的時候,手動在 Header 中設(shè)置 Cookie 。這樣就完美地模擬瀏覽器的 Cookie 概念了。
設(shè)置一個隊列,如果請求處理完畢,則移出隊列,如果當(dāng)前數(shù)組超過10個請求,則進(jìn)入等待狀態(tài)。大概代碼如下:
class Request {
constructor() {
this.maxLimit = 10;
this.requestQueue = []; // 請求隊列
this.requestIng = 0; //當(dāng)前并發(fā)數(shù)
}
request () {
// 判斷是否超出并發(fā)數(shù)
if(this.requestIng >= this.maxLimit) {
// 推入請求隊列
}else {
this.requestIng ++;
// 執(zhí)行成功后 - 1 ,從 requestQueue 中取出重新請求
}
}
}
|
好吧,還是從一張圖說起,顯然,我們可以看出,每一次 setData 都是一次線程通信。

線程通信成本很高,非常耗時間,因此官方明確的給出了建議:
data: {
array: {
changeData: '我改變了',
noChangeData: '我沒有改變'
},
},
this.setData({
'array.changeData':'changed data'
})
|
data: {
view: '與界面相關(guān)的數(shù)據(jù)'
},
noRelaView: '與界面無關(guān)'
復(fù)制代碼
|