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