目前在 async/await 中参入回调式 setData 函数显得非常别扭,举个列子,我希望在请求完成后不论成功与否都处理一些单独的业务逻辑:
try {
const { data: res } = await fetch.getRes('/get', { page: 1, limit: 10 })
if (res.code === 0) {
this.setData({ count: res.data.count, list: res.data.list }, () => {
doSomeThings1()
doSomeThings2()
})
} else {
wx.showToast({ title: res.data.msg, icon: 'none' })
doSomeThings1()
doSomeThings2()
}
} catch (err) {
wx.showToast({ title: '服务器开小差了', icon: 'none' })
doSomeThings1()
doSomeThings2()
}
会看到上面出现了大量重复代码,增加代码阅读成本,降低开发效率。当然,可以单独封装一下逻辑,例如下面这样:
const doThings = () => {
doSomeThings1()
doSomeThings2()
}
try {
const { data: res } = await fetch.getRes('/get', { page: 1, limit: 10 })
if (res.code === 0) {
this.setData({ count: res.data.count, list: res.data.list }, doThings)
} else {
wx.showToast({ title: res.data.msg, icon: 'none' })
doThings()
}
} catch (err) {
wx.showToast({ title: '服务器开小差了', icon: 'none' })
doThings()
}
这时候仍然可以看到出现了三次重复的逻辑。
如果有 setDataAsync 方法,代码看上去会像下面这样更加简洁:
try {
const { data: res } = await fetch.getRes('/path', { page: 1, limit: 10 })
if (res.code === 0) {
await this.setDataSync({ count: res.data.count, list: res.data.list })
} else {
wx.showToast({ title: res.data.msg, icon: 'none' })
}
} catch (err) {
wx.showToast({ title: '服务器开小差了', icon: 'none' })
}
doSomeThings1()
doSomeThings2()
当然,也许可以自己定义一个 setDataAsync 方法,像这样:
Page({
/**
* 异步设置数据
* @param {Record<string, any>} data
* @returns {Promise<void>}
*/
setDataAsync(data) {
return new Promise(resolve => void this.setData(data, resolve))
}
})
可是上面这么做存在一些问题:
- 每个页面/组件都需要手动写上该方法,仍然会增加大量的重复代码。
- 结合 TypeScript 时,无法和 setData 一样获得良好的代码补全(setData 方法可以获得在 data 中定义的属性并自动补全)。
以上是目前我开发时遇到的问题,目前能想到的方案是支持异步 setData,可以考虑两种方式:
- 让原有的 setData 返回 Promise,原有 callback 保持不变。
- 新增 setDataAsync 异步方法。
个人认为第一种方式更好些,希望开发团队考虑下。
有个基础的说明: setData 总体上说是同步的。绝大多数情况下,不需要等到 setData 回调再执行之后的逻辑。(那样反而会拖慢整体的流程,因为 setData 的回调是在渲染线程已经确认界面更新之后,有时会非常非常晚。)
Ps: 未实际测试,可以参考下
你可以挂载 setDataAsync 方法到 app 上
App({ setDataAsync(page, data) { return new Promise(resolve => page.setData(data, resolve)) } }) // page.js getApp().setDataAsync(this, { test: true })
你也可以重写Page来实现每个页面都默认均带 setDataAsync 方法
// wxPage.js const wxPage = () => { const originalPage = Page Page = (config) => { config.setDataAsync = function(data) { return new Promise(resolve => config.setData(data, resolve)) } return originalPage(config) } } module.exports = wxPage() require("./wxPage.js") // page.js this.setDataAsync({ test: true })