你可能不知道的小程序

爲了讓你們更好的理解小程序的一些限制和作一些優化,下面從小程序的基礎架構講起,若有不對的地方,望指正,請輕噴 😄程序員

一. 頁面棧限制最多10層

首先,咱們看看下圖,小程序的架構以下: canvas

咱們能夠看到,一個頁面使用一個 WebView 線程進行渲染。 若是於頁面棧有 10 層,則會開啓 10 個 WebView 線程,佔多一點內存,因此對頁面棧進行了限制。

那若是在10層頁面棧的限制內,因爲頁面的內容過於複雜,內存爆了怎麼辦? 小程序內部有一個回收機制,若是內存緊張時,會回收掉一部分 WebView 。小程序

不少人可能會以爲, 10 層頁面棧基本已經夠用了,無須關注這方面的限制了。數組

可是若是出現循環引用的話,用戶反覆點擊,則很容易出現爆棧的狀況。 以下圖:瀏覽器

因此,在開發以前,提早梳理好頁面之間的跳轉,合理使用 navigator ,redirectTo, navigateBack …… 是很是重要的。

固然,做爲一個程序員,我並不想在跳轉的時候去時時刻刻的關注我有沒有正確引用,有沒有超出10層頁面棧。 徹底能夠對小程序的跳轉作一個封裝。緩存

由於只有 wx.navigateTo 纔會使頁面棧 + 1 ,那咱們只要對這個方法作一層兜底處理便可。 以下代碼:bash

const PAGE_LIMIT = 10
const pages = getCurrentPages()
if(pages.length >= PAGE_LIMIT) {
  // 使用 wx.redirectTo 方法
}
複製代碼

這樣就能夠爲所欲爲的跳來跳去了。cookie

二. JsCore

小程序的邏輯層是在 JsCore 中運行的。限制以下:網絡

  • 沒有 Window、Document 對象,也就沒法使用 基於 DOM 的一些庫. 暫無解決方法。

仍是從一張圖提及: 架構

不一樣於頁面的渲染,全部的腳本邏輯都是跑在同一個 JsCode 線程裏面,相似於路由中改變 Hash 值。 所以也會引發下面一些常見的坑

  1. 須要本身清理頁面的 setTimeout 或者 setInterval 定時器
  2. 若是要求頁面每次出現都是最新的數據,則要把拉取數據的邏輯放在 onShow 中執行,別放在 onload 中。
  3. 若追求「極致化體驗」,在用戶切到下一個頁面的時候,能夠在 onHide 中 abort 掉沒有請求成功的接口,把即將處理的 setData 去掉,能夠減輕最新頁面的邏輯,讓最新頁面最快渲染展現。

三. 原生組件層級最高

像 canvas , video ,input ,map ,picker …… 組件,官方直接使用原生組件,渲染方式以下圖:

從上圖很容易就能夠看出,Navtive 組件的層級是最高的,那麼僅僅去改變 z-index 也沒法讓其餘組件覆蓋原生組件。還好,官方給出了一個解決方案:

  • 使用 cover-view cover-image 將但願層級變高的組件也包裹成「原生組件」

四. 獨特的網絡請求,本地存儲

  1. 獨特的 Storage 存儲
    • 以用戶緯度隔離,同一個設備,A 沒法訪問 B 用戶的數據。
    • 持久緩存,只有在用戶關掉小程序纔會刪除,若是空間不足,會進行 LRU ,也就是不常用的小程序的數據緩存區域會被所有清空。
    • 在體驗版、開發版、和線上版都共用一套,並不會隔離。
    • 沒有 Cookie
  2. Request uploadFile downloadFile 併發最多10個請求
  3. 只支持 HTTPS WSS

若是以往在移動端, PC 的接口會使用 Cookie 進行一些處理,那在小程序中使用該接口就比較尷尬了。

所以,咱們能夠在小程序中也模擬出 Cookie ,以下圖:

在 Storage 中隔離一個字段,用來作 Cookie ,下面用了一個小技巧,把 Cookie 的內容存放於內存中,而非每次都從 storage 中讀取。

let cookie = (function(){
    return wx.getStorageSync('cookies');
}())
const Cooke = {
  getCookie(){}, //從內存中獲取cookie
  setCookie(){}, // 設置cookie
  setCookieInHeader(){}, //根據response的Header設置cookie
  removeCookie() {},  //刪除cookie
  isExpired() {} //判斷是否過時
}
複製代碼

而後,咱們在每次 Request 成功後,解析 Header 中 SET-COOKIE 屬性設置 Cookie ,在每一次請求的時候,手動在 Header 中設置 Cookie 。這樣就完美地模擬瀏覽器的 Cookie 概念了。

  1. 併發請求處理

設置一個隊列,若是請求處理完畢,則移出隊列,若是當前數組超過10個請求,則進入等待狀態。大概代碼以下:

class Request {
    constructor() {
        this.maxLimit = 10;
        this.requestQueue = []; // 請求隊列
        this.requestIng = 0; //當前併發數
    }
    request () {
        // 判斷是否超出併發數
        if(this.requestIng >= this.maxLimit) {
            // 推入請求隊列
        }else {
            this.requestIng ++;
            // 執行成功後 - 1 ,從 requestQueue 中取出從新請求
        }
    }
}
複製代碼

五. setData

好吧,仍是從一張圖提及,顯然,咱們能夠看出,每一次 setData 都是一次線程通訊。

線程通訊成本很高,很是耗時間,所以官方明確的給出了建議:

  1. 將屢次 setData 合併成一次進行調用
  2. 只 setData 對象改變的某個值
data: {
    array: {
        changeData: '我改變了',
        noChangeData: '我沒有改變'
    },
},
this.setData({
    'array.changeData':'changed data'
})
複製代碼
  1. 與界面渲染無關的字段不要放在 data 中
data: {
    view: '與界面相關的數據'
},
noRelaView: '與界面無關'
複製代碼

@Author:beidan

相關文章
相關標籤/搜索