blog
blog copied to clipboard
async await 的错误处理
async await 从语法层面给人一种非常直观的方式,可以让我们避免 callback hell 与 Promise hell 。
async function getUserInfo() {
const id = await request.getCurrentId()
const info = await request.getUserInfo(id)
return info
}
但是每一步 await 的都可能出错,为了捕获这些错误,我们使用 try...catch...
async function getUserInfo (cb) {
try {
const id = await request.getCurrentId()
} catch(e) {
return cb('an error in getCurrentId')
}
try {
const info = await request.getUserInfo(id)
} catch(e) {
return cb('an error in getUserInfo')
}
return cb(null, info)
}
这样写一眼看上去代码异常丑陋而且不直观,国外大神 Dima 在他的文章 how-to-write-async-await-without-try-catch-blocks-in-javascript 中提到了一种解决方案,因为 await
实际上等待的是一个 Promise
,因此可以使用一个函数包装一个来符合 error first
的原则,从而避免 try...catch...
function to (promise) {
return promise.then(data => {
return [null, data]
}).catch(err => [err])
}
通过这个函数包装一下上面的例子
async function getUserInfo () {
let err, id, info;
[err, id] = await to(request.getCurrentId())
if(err) return console.error(err)
[err, info] = await to(request.getUserInfo(id))
if(err) return console.error(err)
return info
}
基于这种思路,可以想到直接在每一步 await
的时候都单独 catch
, 最后在最外层捕获 error
async function getUserInfo() {
try {
const id = await request.getCurrentId().catch(err => Promise.reject('an error in getCurrentId'))
const info = await request.getUserInfo(id).catch(err => Promise.reject('an error in getUserInfo'))
} catch(err) {
errorHandle(err)
}
}
在实际编码中,我们当然想要一个公共的 error
处理函数,不过如果你的业务太复杂了,偶尔中途需要有额外的处理逻辑也没关系,别忘了 Promise.reject()
啥都可以作为参数:
async function getUserInfo() {
try {
const id = await request.getCurrentId().catch(err => Promise.reject('an error in getCurrentId'))
const info = await request.getUserInfo(id).catch(err => Promise.reject(() => {
doSomething()
anotherErrorHandler()
})
} catch(err) {
if (typeof err === 'function') err()
else errorHandle(err)
}
}
Dima 的处理方式已经很不错了,市面上有非常多的基于这种思想的库,可以在 npm 上 搜索,如果简单拓展下自定义 error 的信息(如code,msg),是否采用 errorFirst 的惯例,如下:
function to (promise, errorProps = {}, errorFirst = true) {
return promise.then((data) => errorFirst ? [null, data] : [data, null])
.catch(err => {
if(errorProps) Object.assign(err, errorProps)
errorFirst ? [err, undefined] : [undefined, err]
})
}
大概关于 async
await
的错误处理就总结如上了,以后遇到更好地处理方式再说。