原理

2018-06-17 16:26 更新

在針對(duì)數(shù)據(jù)綁定做優(yōu)化時(shí),需要先了解小程序的運(yùn)行機(jī)制。因?yàn)橐晥D層與邏輯層的完全分離,所以二者之間的通信全都依賴于 WeixinJSBridge 實(shí)現(xiàn)。如:

  • 開(kāi)發(fā)者工具中是基于 window.postMessage
  • IOS中基于 window.webkit.messageHandlers.invokeHandler.postMessage
  • Android中基于WeixinJSCore.invokeHandler

因此數(shù)據(jù)綁定方法this.setData也如此,頻繁的數(shù)據(jù)綁定就增加了通信的成本。再來(lái)看看this.setData究竟做了哪些事情。基于開(kāi)發(fā)者工具的代碼,單步調(diào)試大致還原出完整的流程,以下是還原后的代碼:

/*
setData 主流程精簡(jiǎn)還原,并非完整主流程,內(nèi)有注釋
*/
function setData (obj) {
    if (typeof(obj) !== 'Object') {
        console.log('類型錯(cuò)誤'); // 并沒(méi)有預(yù)期中的return;
    }
    let type = 'appDataChange';
    
    // u.default.emit(e, this.__wxWebviewId__) 代碼還原
    let e = [type, {
                data: {data: list}, 
                options: {timestamp: +new Date()}
            },
            [0] // this.__wxWebviewId__
    }];

    // WeixinJSBridge.publish.apply(WeixinJSBridge, e); 代碼還原
    var datalength = JSON.stringify(e.data).length;  // 第一次 JSON.stringify
    if (datalength > AppserviceMaxDataSize) { // AppserviceMaxDataSize === 1048576
        console.error('已經(jīng)超過(guò)最大長(zhǎng)度');
        return;
    }

    if (type === 'appDataChange' || type === 'pageInitData' || type === '__updateAppData') {

        // sendMsgToNW({appData: __wxAppData, sdkName: "send_app_data"}) 代碼還原
        __wxAppData = {
            'pages/page1/page1': alldata
        }
        e = { appData: __wxAppData, sdkName: "send_app_data" }
       
        var postdata = JSON.parse(JSON.stringify(e)); // 第二次 JSON.stringify 第一次 JSON.parse
        window.postMessage({
            postdata
        }, "*");
    }


    // sendMsgToNW({appData: __wxAppData, sdkName: "send_app_data"}) 代碼還原
    e = {
        eventName: type,
        data: e[1],
        webviewIds: [0],
        sdkName: 'publish'
    };

    var postdata = JSON.parse(JSON.stringify(e));  // 第三次 JSON.stringify 第二次 JSON.parse
    window.postMessage({
        postdata
    }, "*");
}

setData 運(yùn)行的流程如下:

圖片描述

從上面代碼以及流程圖中可以看出,在一次setData({a: 1})作時(shí),會(huì)進(jìn)行三次 JSON.stringify,二次JSON.parse以及兩次window.postMessage操作。并且在第一次window.postMessage時(shí),并不是單單只處理傳遞的{a:1},而是處理當(dāng)前頁(yè)面的所有 data 數(shù)據(jù)。因此可想而知每次setData操作的開(kāi)銷是非常大的,只能通過(guò)減少數(shù)據(jù)量,以及減少setData操作來(lái)規(guī)避。

與 setData 相近的是 React 的 setState 方法,同樣是使用 setState 去更新視圖的,可以通過(guò)源碼 React:L199 看到 setState的關(guān)鍵代碼如下:

function enqueueUpdate(component) {
  ensureInjected();
  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
  dirtyComponents.push(component);
}

setState的工作流程如下:

圖片描述

可以看出,setState 加入了一個(gè)緩沖列隊(duì),在同一執(zhí)行流程中進(jìn)行多次 setState 之后也不會(huì)重復(fù)渲染視圖,這就是一種很好的優(yōu)化方式。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)