為了讓大家更(geng)好的(de)理解小程(cheng)序的(de)一些限(xian)制和做一些優化,下(xia)面從(cong)小程(cheng)序的(de)基礎(chu)架(jia)構講(jiang)起,如有不(bu)對的(de)地(di)方(fang),望指正,請輕噴 :smile:
首先,我們看看下圖(tu),小程序的架構(gou)如下:

我們(men)可(ke)以看到,一(yi)(yi)個(ge)(ge)(ge)頁面(mian)使用一(yi)(yi)個(ge)(ge)(ge) WebView 線程進行渲染。 如果于頁面(mian)棧有 10 層,則會開啟 10 個(ge)(ge)(ge) WebView 線程,占多一(yi)(yi)點(dian)內存,所以對頁面(mian)棧進行了限制。
那如果(guo)(guo)在(zai)10層頁面棧的限(xian)制內,由于(yu)頁面的內容過于(yu)復(fu)雜,內存爆了怎么辦? 小程序(xu)內部有一(yi)個回收機制,如果(guo)(guo)內存緊張時,會(hui)回收掉一(yi)部分 WebView 。
很多(duo)人可能(neng)會(hui)覺得, 10 層頁面(mian)(mian)棧(zhan)基本已經夠(gou)用了,無須關注這(zhe)方面(mian)(mian)的限制了。
但是(shi)如(ru)果出(chu)現循環引用的話,用戶(hu)反復點擊,則很容易出(chu)現爆棧的情況。 如(ru)下圖:

所以,在開發之(zhi)前,提前梳理(li)好頁面之(zhi)間的(de)跳轉,合理(li)使用 navigator ,redirectTo, navigateBack …… 是非常重要的(de)。
當然(ran),作為一(yi)個程(cheng)序(xu)員,我并(bing)不(bu)想在跳(tiao)轉(zhuan)(zhuan)的(de)時候(hou)去時時刻刻的(de)關注我有沒有正確引用,有沒有超出(chu)10層頁(ye)面棧。 完全可以對小程(cheng)序(xu)的(de)跳(tiao)轉(zhuan)(zhuan)做一(yi)個封裝。
因為只有 wx.navigateTo 才(cai)會使頁面棧 + 1 ,那我(wo)們只要對這個方法做一層兜底處(chu)理即可。 如下代碼:
const PAGE_LIMIT = 10
const pages = getCurrentPages()
if(pages.length >= PAGE_LIMIT) {
// 使用 wx.redirectTo 方法
}
|
這樣就(jiu)可以隨心(xin)所(suo)欲的(de)跳來跳去了。
小程序的邏輯層(ceng)是在 JsCore 中運(yun)行的。限制如(ru)下:
還是從一張圖(tu)說起:

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

從上圖很容易就可以看出,Navtive 組件(jian)的層(ceng)級是(shi)最高的,那么僅僅去改變 z-index 也無法讓其他組件(jian)覆蓋(gai)原(yuan)生組件(jian)。還(huan)好,官(guan)方(fang)給(gei)出了(le)一個解(jie)決(jue)方(fang)案:
如果(guo)以往在(zai)移動端, PC 的接口會使用(yong) Cookie 進行一些(xie)處(chu)理,那在(zai)小(xiao)程序中使用(yong)該接口就比(bi)較(jiao)尷尬了。
因此,我們(men)可(ke)以在小(xiao)程序(xu)中也模擬出(chu) Cookie ,如下圖(tu):

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

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