问答题690/1593async/await 怎么进行错误处理?

难度:
2022-05-16 创建

参考答案:

一般情况下 async/await 在错误处理方面,主要使用 try/catch,像这样

1const fetchData = () => { 2 return new Promise((resolve, reject) => { 3 setTimeout(() => { 4 resolve('fetch data is me') 5 }, 1000) 6 }) 7} 8 9(async () => { 10 try { 11 const data = await fetchData() 12 console.log('data is ->', data) 13 } catch(err) { 14 console.log('err is ->', err) 15 } 16})() 17

这么看,感觉倒是没什么问题,如果是这样呢?有多个异步操作,需要对每个异步返回的 error 错误状态进行不同的处理,以下是示例代码

1const fetchDataA = () => { 2 return new Promise((resolve, reject) => { 3 setTimeout(() => { 4 resolve('fetch data is A') 5 }, 1000) 6 }) 7} 8 9const fetchDataB = () => { 10 return new Promise((resolve, reject) => { 11 setTimeout(() => { 12 resolve('fetch data is B') 13 }, 1000) 14 }) 15} 16 17const fetchDataC = () => { 18 return new Promise((resolve, reject) => { 19 setTimeout(() => { 20 resolve('fetch data is C') 21 }, 1000) 22 }) 23} 24 25(async () => { 26 try { 27 const dataA = await fetchDataA() 28 console.log('dataA is ->', dataA) 29 } catch(err) { 30 console.log('err is ->', err) 31 } 32 33 try { 34 const dataB = await fetchDataB() 35 console.log('dataB is ->', dataB) 36 } catch(err) { 37 console.log('err is ->', err) 38 } 39 40 try { 41 const dataC = await fetchDataC() 42 console.log('dataC is ->', dataC) 43 } catch(err) { 44 console.log('err is ->', err) 45 } 46})() 47

这样写代码里充斥着 try/catch,有代码洁癖的你能忍受的了吗?这时可能会想到只用一个 try/catch。

1// ... 这里 fetch 函数省略 2 3(async () => { 4 try { 5 const dataA = await fetchDataA() 6 console.log('dataA is ->', dataA) 7 const dataB = await fetchDataB() 8 console.log('dataB is ->', dataB) 9 const dataC = await fetchDataC() 10 console.log('dataC is ->', dataC) 11 } catch(err) { 12 console.log('err is ->', err) 13 // 难道要定义 err 类型,然后判断吗?? 14 /** 15 * if (err.type === 'dataA') { 16 * console.log('dataA err is', err) 17 * } 18 * ...... 19 * */ 20 } 21})() 22

如果是这样写只会增加编码的复杂度,而且要多写代码,这个时候就应该想想怎么优雅的解决,async/await 本质就是 promise 的语法糖,既然是 promise 那么就可以使用 then 函数了

1(async () => { 2 const fetchData = () => { 3 return new Promise((resolve, reject) => { 4 setTimeout(() => { 5 resolve('fetch data is me') 6 }, 1000) 7 }) 8 } 9 10 const data = await fetchData().then(data => data ).catch(err => err) 11 console.log(data) 12})() 13

在上面写法中,如果 fetchData 返回 resolve 正确结果时,data 是我们要的结果,如果是 reject 了,发生错误了,那么 data 是错误结果,这显然是行不通的,再对其完善。

1(async () => { 2 const fetchData = () => { 3 return new Promise((resolve, reject) => { 4 setTimeout(() => { 5 resolve('fetch data is me') 6 }, 1000) 7 }) 8 } 9 10 const [err, data] = await fetchData().then(data => [null, data] ).catch(err => [err, null]) 11 console.log('err', err) 12 console.log('data', data) 13 // err null 14 // data fetch data is me 15})() 16

这样是不是好很多了呢,但是问题又来了,不能每个 await 都写这么长,写着也不方便也不优雅,再优化一下

1(async () => { 2 const fetchData = () => { 3 return new Promise((resolve, reject) => { 4 setTimeout(() => { 5 resolve('fetch data is me') 6 }, 1000) 7 }) 8 } 9 10 // 抽离成公共方法 11 const awaitWrap = (promise) => { 12 return promise 13 .then(data => [null, data]) 14 .catch(err => [err, null]) 15 } 16 17 const [err, data] = await awaitWrap(fetchData()) 18 console.log('err', err) 19 console.log('data', data) 20 // err null 21 // data fetch data is me 22})() 23

将对 await 处理的方法抽离成公共的方法,在使用 await 调用 awaitWrap 这样的方法是不是更优雅了呢。如果使用 typescript 实现大概是这个样子

1function awaitWrap<T, U = any>(promise: Promise<T>): Promise<[U | null, T | null]> { 2 return promise 3 .then<[null, T]>((data: T) => [null, data]) 4 .catch<[U, null]>(err => [err, null]) 5}

最近更新时间:2024-08-10

赞赏支持

预览

题库维护不易,您的支持就是我们最大的动力!