zoukankan      html  css  js  c++  java
  • await的错误处理问题,一个issue引发的ts社区的讨论

    前提

    大家都知道try-catch对异步流程中的错误有时候是捕捉不到的,eg:

    function func1() {
      try {
        func2();
      } catch (error) {
        console.log('error');
      }
    }
    
    function func2() {
      setTimeout(() => {
        throw new Error('error')
      }, 1000)
    }
    
    func1();
    
    

    执行这些代码,你会发现过了一秒后程序直接报错,console.log('error')并没有执行,也就是func1并没有捕捉到func2的异常。这就是异步的问题所在。

    我们一般的做法就是直接加上async/await:

    async function func1() {
      try {
        await func2();
      } catch (error) {
        console.log('error');
      }
    }
    
    function func2() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          reject()
        }, 1000)
      })
    }
    
    func1();
    
    

    func2被Promise封装,reject后会被func1的try-catch捕获到,像现在的axios很多库都已经封装好Promise方便直接await。

    问题

    这里我们要讨论的就是对await到底用try-catch,if(err)的方式。

    if(err)的方式在node中的很多异步回调函数中很多场景都用到,err永远是node结果回调函数的第一个参数,但此情景又与node中的不一样。对await的错误处理要想获取到err,需要额外增加一个函数,用try-catch捕获到的err return出去。
    eg:
    每次使用都要引用errCatch()。

    async function errCatch(asyncFunc) {
        try {
            let res = await asyncFunc();
            retrun [null, res]
        } catch (error) {
            return [error,null];
        }
    }
    

    这样func1就要写成:

    async function func1() {
      let [err, res] = errCatch(asyncFunc);
      if (err) {
        //.....
      }
    }
    

    那么这种写法比直接try-catch有什么好处,第一点就是更加语义化了,这个问题在deno社区就这个问题的ts写法引起过讨论,可以看看这个issue:

    https://github.com/denoland/deno_std/issues/525

    在这里插入图片描述
    在这里插入图片描述
    第一个意思是 Golang 只需要处理 return 出来的错误,很少有运行时错误,即便有,也是可以在 defer 统一处理。 第二个意思是,像一个读流 copy 到另一个写流。假如因为某个异常中断的话,我们需要知道是读取到了第 n 的细节中断的,然后错误是什么。这样的场景就适合这样使用。(具体可以再copy中实现)
    (但我觉得这个其实是特殊场景,用try-catch也能控制)
    在这里插入图片描述
    其实一个老哥也指出传统的promise做法,因为await的错误不捕获会导致整个async函数的中断,用catch也能避免中断并捕捉到错误。

    开issue的作者是说使用这种style的原因是这样的:
    在这里插入图片描述
    最后维护者是这么说的:
    在这里插入图片描述
    大概意思就是说
    “我们可以在utils/async.ts中实现这一点,供我们自己使用,并作为用户的一个选项提供。但正如我所说,在更多的情况下,Try-Catch是进入JS的正确方法,或者提供像上面提到的@J-F1这样的catch处理程序。
    (作为一个夸张的例子,C中的全局errno在某些情况下可能更干净,但是我们在JS中不做这样的构造,因为它违背了预期的语言用法。
    如果您认为这些助手非常有用,那么如果您能够贡献并提交一个pr来将它们添加到utils/async.ts中,这将是非常好的,并且有可能在将来说服更多的JS开发人员尝试这样的处理方式,这样有一天它就足够惯用了。
    (我目前受到一些法律纠纷的约束,因此不幸的是,我自己做不到。)”

    其实上面issue作者举的那个例子就是说在官方库中有些错误不用被处理,只是做检测的情况下,不用写try-catch,catch的e就更不用写上了,用了helper的style后,可以直接这样写:

    const statInfo = await maybe(stat(fn)); // yields FileInfo | null 
    const mode = statInfo ? statInfo.mode : null;
    

    看上去更加舒服???

    知乎上关于node.js 应该 return new Error() 还是 throw new Error()的讨论

    后面突然想到了之前看到的一个话题的讨论,其实和这个很像,某种程度甚至是一样的了:
    node.js 应该 return new Error() 还是 throw new Error()?

    参考:
    https://www.zhihu.com/question/323618147
    https://juejin.im/post/5d25b39bf265da1bb67a4176
    https://github.com/denoland/deno_std/issues/525
    http://es6.ruanyifeng.com/#docs/async

  • 相关阅读:
    Qt 之 emit、signals、slot的使用
    qt中的 connect 函数
    进程同步:生产者消费者模型 以及解决方法
    Linux 时间 与 定时器
    Linux 环境编程:errno的基本用法
    Linux 环境编程:dirfd参数 有关解析
    Kubernetes设计理念
    禅道升级
    关闭自动更新
    linux下的特殊模式
  • 原文地址:https://www.cnblogs.com/zhangmingzhao/p/11182057.html
Copyright © 2011-2022 走看看