Skip to content

[js] 第103天 你是如何更好地处理Async/Await的异常的? #994

Open
@haizhilin2013

Description

@haizhilin2013
Collaborator

第103天 你是如何更好地处理Async/Await的异常的?

Activity

xxf1996

xxf1996 commented on Jul 28, 2019

@xxf1996

我一般直接在await后面的Promise对象上使用catch方法;不过更优雅的方式应该是对promise对象进行一层包装,通过返回值判断是否有异常,如:

// 对Promise对象进行一层包装,将异常值和成功结果一起返回
function wrapper(promise) {
  return promise
    .then(res => [null, res])
    .catch(err => [err, null])
}

function sleep(t) {
  return new Promise((resolve, reject) => {
    if (t < 1000) {
      reject('123')
    } else {
      setTimeout(() => {
        resolve()
      }, t)
    }
  })
}

async function delay() {
  let [err, res] = await wrapper(sleep(100))
  if (err) {
    console.log(`error: ${err}`)
  }
}

delay()

参考文档:async/await 优雅的错误处理方法 - 掘金

ghost

ghost commented on Jul 28, 2019

@ghost

@xxf1996 你好,
关于你描述的错误处理方法,我并没有发现它的优雅之处。
考虑以下两份代码,我认为上面的代码更为优雅一些。

try {
    const data = await asyncFn()
    /* do sth w/ data */
} catch (err) {
    /* handle err */
}
const [data, err] = await asyncFn()
if (data) {
    /* do sth w/ data */
} else {
    /* handle err */
}
xxf1996

xxf1996 commented on Jul 28, 2019

@xxf1996

@xxf1996 你好,
关于你描述的错误处理方法,我并没有发现它的优雅之处。
考虑以下两份代码,我认为上面的代码更为优雅一些。

try {
    const data = await asyncFn()
    /* do sth w/ data */
} catch (err) {
    /* handle err */
}
const [data, err] = await asyncFn()
if (data) {
    /* do sth w/ data */
} else {
    /* handle err */
}

嗯,确实没啥特别优雅的,都需要套一层;一般情况用try/catch就够用了。

HCLQ

HCLQ commented on Jul 28, 2019

@HCLQ

@xxf1996 你好,
关于你描述的错误处理方法,我并没有发现它的优雅之处。
考虑以下两份代码,我认为上面的代码更为优雅一些。

try {
    const data = await asyncFn()
    /* do sth w/ data */
} catch (err) {
    /* handle err */
}
const [data, err] = await asyncFn()
if (data) {
    /* do sth w/ data */
} else {
    /* handle err */
}

玩node时。。他那么写还是比较常见的。。

ghost

ghost commented on Jul 28, 2019

@ghost

@HCLQ

玩node时。。他那么写还是比较常见的。。

你是指 callback 中使用的 error-first 的错误处理方式吗?

functionWithCallback(..., function (err, data) {
    if (err) ...
    else ...
})

这种的确是常见,但是返回 Promise<[Error?, any?]>async function 我真的没见过。或许可以给些例子?

johnsoncheg

johnsoncheg commented on Jul 29, 2019

@johnsoncheg

@t532 包装写法可以省去你每次都需要再具体位置使用try ... catch或者.catch

jialinhome

jialinhome commented on Jul 29, 2019

@jialinhome
  1. awaittry...catch
async function f() {
  try {
    let response = await fetch('http://no-such-url');
  } catch(err) {
    alert(err); 
  }
}
f();
  1. 由于async函数必然返回一个Promose,所以可以在执行async函数后加入.catch
async function f() {
  let response = await fetch('http://no-such-url');
}
f().catch(alert); 
  1. 如果前两种错误捕获方式都忘记了,可以监听unhandledrejection 进行捕获
window.addEventListener('unhandledrejection', function(event) {
  // the event object has two special properties:
  alert(event.promise); // [object Promise] - the promise that generated the error
  alert(event.reason); // Error: Whoops! - the unhandled error object
});

参考:
Async/await

EmiyaYang

EmiyaYang commented on Jul 29, 2019

@EmiyaYang

关于两种写法优劣的,可以看看一下这篇外网文章How to write async await without try-catch blocks in Javascript。文章作者可能也是这种写法的创始者,他从go-lang编程中获得灵感,使用ts造了相应的轮子:await-to-js

ghost

ghost commented on Jul 30, 2019

@ghost

@EmiyaYang

关于两种写法优劣的,可以看看一下这篇外网文章How to write async await without try-catch blocks in Javascript。文章作者可能也是这种写法的创始者,他从go-lang编程中获得灵感,使用ts造了相应的轮子:await-to-js

Golang 的错误处理方式好处是可以不用被强迫在错误发生时即进行处理,然而却无法在同一个地方 handle 多个错误(除了 ErrorGroup 这种丑陋的方式)。所以两种方式都各有优劣,还是看需求用吧。这篇博客的作者也写了:

This post is just a different way of looking on async/await error handling. It should not be used as a goto for every async/await function you write and in a lot cases having a single catch at the top will do just fine. Sometimes we don't want to expose the error object of the implementation of the model and want instead to provide a custom error object masking the underlying mongoose error implementation.

EragonBubble

EragonBubble commented on Aug 1, 2019

@EragonBubble

try-catch

Kntt

Kntt commented on Aug 10, 2019

@Kntt

我使用装饰器来处理, 避免重复写trycatch

主要针对vue这样的框架,通过class使用的
使用方法

const CatchError = (errFunc?: ((ctx: any, err: Error) => void)): MethodDecorator => {
  return function (target, propertyKey, descriptor: PropertyDescriptor) {
    let method = descriptor.value
    descriptor.value = async function (...args) {
      try {
        await method.apply(this, args)
      } catch (error) {
        if (errFunc) {
          errFunc(this, error)
        } else {
          console.log(`[Error] 统一处理${String(propertyKey)}`, error)
        }
      }
    }
  }
}

const wrapper = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() < 0.2) {
        resolve({
          name: 'world'
        })
      } else {
        reject(new Error('is a err'))
      }
    }, 1000)
  })
}
class Test {
  name: string = 'hello'

  // 自己处理错误
  @CatchError((ctx, err) => {
    console.log('自己处理错误:', err,'\nthis指向:', ctx)
  })
  async runSelf () {
    const data = await wrapper()
    console.log('收到数据:', data)
  }
  // 统一处理错误
  @CatchError()
  async runCommon () {
    const data = await wrapper()
    console.log('收到数据:', data)
  }
}

const t = new Test()

t.runSelf()
t.runCommon()
assmdx

assmdx commented on Dec 11, 2019

@assmdx

@xxf1996 写的挺好的,每次写代码的时候总感觉大括号的嵌套层数和代码的不稳定性成正比。。

smile-2008

smile-2008 commented on Sep 30, 2021

@smile-2008
  1. awaittry...catch
async function f() {
  try {
    let response = await fetch('http://no-such-url');
  } catch(err) {
    alert(err); 
  }
}
f();
  1. 由于async函数必然返回一个Promose,所以可以在执行async函数后加入.catch
async function f() {
  let response = await fetch('http://no-such-url');
}
f().catch(alert); 
  1. 如果前两种错误捕获方式都忘记了,可以监听unhandledrejection 进行捕获
window.addEventListener('unhandledrejection', function(event) {
  // the event object has two special properties:
  alert(event.promise); // [object Promise] - the promise that generated the error
  alert(event.reason); // Error: Whoops! - the unhandled error object
});

参考: Async/await

xiaoqiangz

xiaoqiangz commented on Jun 28, 2022

@xiaoqiangz

try {
const data = await asyncFn()
/* do sth w/ data /
} catch (err) {
/
handle err */
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    jsJavaScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @smile-2008@haizhilin2013@johnsoncheg@HCLQ@xiaoqiangz

        Issue actions

          [js] 第103天 你是如何更好地处理Async/Await的异常的? · Issue #994 · haizlin/fe-interview