先科普下 setData 做的事情:
在數據傳輸時,邏輯層會執行一次 JSON.stringify 來去除掉 setData 數據中不可傳輸的部分,之後將數據發送給視圖層。同時,邏輯層還會將 setData 所設置的數據字段與 data 合併,使開發者可以用 this.data 讀取到變更後的數據。
因此頻繁調用,視圖會一直更新,阻塞用戶交互,引發性能問題。
但頻繁調用是常見開發場景,能不能頻繁調用的同時,視圖延遲更新呢?
參考 Vue,我們能知道,Vue 每次賦值操作並不會直接更新視圖,而是緩存到一個數據更新隊列中,異步更新,再觸發渲染,此時多次賦值,也只會渲染一次。
於是有網友就給出了這套方案的實現方法:
let newState = null
const asyncSetData = ({
vm,
newData,
}) => {
newState = {
...newState,
...newData,
}
Promise.resolve().then(() => {
if (!newState) return
vm.setData({
...newState,
})
newState = null
})
}
由於異步代碼會在同步代碼執行完後執行,因此多次 asyncSetData 的 newData 都會緩存在 newState 中,並在異步的 promise.then 中只 setData 一次。
但這個方案會帶來新的問題:就是同步代碼會阻塞頁面的渲染。
同步代碼會阻塞頁面的渲染的問題其實在瀏覽器中也存在,但在小程序中,由於是邏輯、視圖雙線程架構,因此邏輯並不會阻塞視圖渲染,這是小程序的優點,但在這套方案將會丟失這個優點。
參考資料
- 終極蛇皮上帝視角之微信小程序之告別 setData, 佯真愚, 2018年08月12日