微信小程序中有大量接口是异步调用,异步调用存在着大量问题,稍有不慎就会陷入回调地狱。或者存在后台逻辑获取不到前面程序数据结果,导致程序报错。
想用async/await解决还要NPM第三方插件,流程也比较繁琐。还好自从开发者工具升级后,这个问题变得简单了。废话不多说,直接干货
第一步 配置支持
开发者工具,详情,本地设置中勾选增强编译,这样就OK了。简单吧。
赶快来段代码测试下你的生效没有。
(async () => {
const p = await new Promise(resolve => {
setTimeout(() => resolve("hello async/await"), 1000);
});
console.log(p);
})();
当你在调试工具里看到这个输出时,表明你的这个设置已经生效了。可以放心大胆的用。
hello async/await
第二步 改造异步函数
虽然 async/await 得到了支持,但是还得把 wx.abcd() 封装成 Promise 风格才行。
Node.js 在 util 模块中提供了 promisify 来把 Node.js 风格的回调转换成 Promise 风格,但显然它不适用于 wx 风格。还是自己动手吧,也不用考虑太多。promisify() 就是一个封装函数,传入原来的 wx.abcd 作为参加,返回一个 Promise 风格的新函数。
function toAsync(names) {
// 这里 names 期望是一个数组
return (names || [])
.map(name => (
{
name,
member: wx[name]
}
))
.filter(t => typeof t.member === "function")
.reduce((r, t) => {
r[t.name] = promisify(wx[t.name]);
return r;
}, {});
}
封装好就可以使用
const awx = toAsync(["login", "request"]);
await awx.login();
await awx.request({...});
有些人可能更习惯单个参数传入的方式,像这样
const awx = toAsync("login", "request");
那么在 toAsync 的定义中,参数改为 ...names 就好,即
function toAsync(...names) { ... }
还没完,因为我不想在每一个 js 文件中去 import { toAsync } from ... 。所以把它在 App.onLaunch() 中把它注入到 wx 对象中去,就像这样
App({
onLaunch: function() {
// ...
wx.async = toAsync;
// ...
}
});
改 Promise 类的原形
Promise.prototype.ignoreError = function() {
return this.catch(() => { });
};
这段代码放在定义 toAsync() 之前就好。
用起来也像那么回事
const res = await awx
.getStorage({ key: "blabla" })
.ignoreError();
对于单个 await 异步调用,如果不想写 try ... catch ... 块,还可以自己定义一个 ifError(fn) 来处理错误的情况。但是如果需要批量处理错误,还是 try ... catch ... 用起顺手:
try {
const storeValue = await awx.getStorage({});
const settings = await awx.getSetting();
const { code } = await awx.login();
const userInfo = await awx.getUserInfo({ code });
} catch (err) {
// 处理错误吧
}