Summarization and optimization of async/await error handling methods

Keywords: Java TypeScript

Xiaobian recommends: Fundebug Provide JS error monitoring, Wechat applet error monitoring, Wechat game error monitoring, Node.j error monitoring and Java error monitoring. It's really a very useful error monitoring fee service, which is used by many big companies.

Preface

The world of node.js, starting with callback, does not end with async.

This article will give you a detailed introduction about the elegant error handling of async/await. Let's take a look at the details below.

Error handling of async/await

Typically, async/await uses try/catch for error handling, like this

const fetchData = () => {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
   resolve('fetch data is me')
  }, 1000)
 })
}
 
(async () => {
 try {
  const data = await fetchData()
  console.log('data is ->', data)
 } catch(err) {
  console.log('err is ->', err)
 }
})()

In this way, it's no problem to feel, if so? There are several asynchronous operations that require different handling of error error status returned from each asynchronous operation. Here is the sample code

const fetchDataA = () => {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
   resolve('fetch data is A')
  }, 1000)
 })
}
 
const fetchDataB = () => {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
   resolve('fetch data is B')
  }, 1000)
 })
}
 
const fetchDataC = () => {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
   resolve('fetch data is C')
  }, 1000)
 })
}
 
(async () => {
 try {
  const dataA = await fetchDataA()
  console.log('dataA is ->', dataA)
 } catch(err) {
  console.log('err is ->', err)
 }
 
 try {
  const dataB = await fetchDataB()
  console.log('dataB is ->', dataB)
 } catch(err) {
  console.log('err is ->', err)
 }
 
 try {
  const dataC = await fetchDataC()
  console.log('dataC is ->', dataC)
 } catch(err) {
  console.log('err is ->', err)
 }
})()

There's a lot of try/catch in the code. Can you stand code cleanliness? At this point, you might think of using only one try/catch.

// ... the fetch function is omitted here
 
(async () => {
 try {
  const dataA = await fetchDataA()
  console.log('dataA is ->', dataA)
  const dataB = await fetchDataB()
  console.log('dataB is ->', dataB)
  const dataC = await fetchDataC()
  console.log('dataC is ->', dataC)
 } catch(err) {
  console.log('err is ->', err)
  // Are err types defined and judged?
  /**
   * if (err.type === 'dataA') {
   * console.log('dataA err is', err)
   * }
   * ......
   * */
 }
})()

If writing in this way will only increase the complexity of coding, but also to write more code, then we should think about how to gracefully solve the problem. The essence of async/await is promise's grammatical sugar, since it is promise, then we can use the then function.

(async () => {
 const fetchData = () => {
  return new Promise((resolve, reject) => {
   setTimeout(() => {
    resolve('fetch data is me')
   }, 1000)
  })
 }
 
 const data = await fetchData().then(data => data ).catch(err => err)
 console.log(data)
})()

In the above way, if fetchData returns the correct result of resolve, data is the result we want, if reject, error occurs, then data is the wrong result, which is obviously not feasible, and then improve it.

(async () => {
 const fetchData = () => {
  return new Promise((resolve, reject) => {
   setTimeout(() => {
    resolve('fetch data is me')
   }, 1000)
  })
 }
 
 const [err, data] = await fetchData().then(data => [null, data] ).catch(err => [err, null])
 console.log('err', err)
 console.log('data', data)
 // err null
 // data fetch data is me
})()

Is that a lot better, but the problem arises again. Not every await can be written so long, and it is inconvenient to write, so let's optimize it again?

(async () => {
 const fetchData = () => {
  return new Promise((resolve, reject) => {
   setTimeout(() => {
    resolve('fetch data is me')
   }, 1000)
  })
 }
 
 // Extraction into a common method
 const awaitWrap = (promise) => {
  return promise
   .then(data => [null, data])
   .catch(err => [err, null])
 }
 
 const [err, data] = await awaitWrap(fetchData())
 console.log('err', err)
 console.log('data', data)
 // err null
 // data fetch data is me
})()

Isn't it more elegant to use await to call awaitWrap by extracting the methods that await handles into common methods? If you use typescript, it's probably like this

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



Author: Yishuiren goes to the bright moon like frost
Link: https://www.jianshu.com/p/7c4c375d71ad

Posted by cmccomas on Fri, 10 May 2019 23:34:38 -0700