如何捕获异步非承诺错误? (对特定错误做出反应)

Posted

技术标签:

【中文标题】如何捕获异步非承诺错误? (对特定错误做出反应)【英文标题】:How can I catch asynchronous-non-promised errors ? ( react to that specific error) 【发布时间】:2018-05-28 06:37:11 【问题描述】:

我知道那里有答案,但我没有找到针对我的实际问题的具体答案。

目前我use下面的模式很多:

 class A
 
     getLocation()
     
         return Promise.reject(2222222)
     
     async a()
     
         try
         
             var loc = await this.getLocation();
             alert(loc)
         
         catch (e)
         
             alert("catch 2")
         
     
 
 new A().a();
结果:“catch 2”

如果我在getLocation 中抛出错误:

  getLocation()
     
         throw Error("ffffff")
     

- 我得到相同的结果 - 没关系。

那么问题出在哪里?

如您所知,asynchronously-non-promised 引发的错误是另一头野兽:

所以this code won't be catched:

  getLocation() //bad code from a third party code , third party code
   
      return new Promise((v, x) => setTimeout(() =>
      
          throw Error("ffffff")
      , 100))
  

问题:

关于我想捕捉错误的事实 - 是否有更好的模式来捕捉这个?

当然可以:

window.onerror = function ()  alert(4)

但这不符合 .catch(...)catch() 的流程,我将无法针对导致错误的那个特定操作执行操作。

全面披露: 没有真实的生活场景。学习目的。

【问题讨论】:

【参考方案1】:

应该在错误发生的地方发现错误。

这种代码代码不正确,应该就地修复:

  getLocation() //bad code from a third party code
   
      return new Promise((v, x) => setTimeout(() =>
      
          throw Error("ffffff")
      , 100))
  

如果这是第三方代码,可以分叉或修补。

正如问题已经提到的那样,onerror 可以全局跟踪异常。这应该只用于通知开发人员存在的错误,而不是以正常方式处理它们。

unhandledrejection 事件可用于相同目的来通知承诺中未处理的拒绝。它将无法处理上面截图中的错误,因为它被抛出在 setTimeout 回调中并且不会导致 promise 被拒绝。

【讨论】:

【参考方案2】:

我猜基本用法是这样的:

class A 
  getLocation(x) 
    return new Promise((resolve, reject) => setTimeout(() => 
      // a lot of async code
      try 
        //simulate unexpected exception    
        if (x === 2) 
          throw ("code error");
        
        if (x) 
          resolve('success');
         else 
          reject('conditional rejection');
        
       catch (ex) 
        reject(ex);
      
    , 1000));
  
  async a(x) 
    await this.getLocation(x).then((loc) => console.info(loc)).catch((e) => console.error(e));
  

let o = new A();
o.a(2);
o.a(0);
o.a(1);

Promise 的拒绝不一定是代码 Exception,代码 Exception 也不一定会触发 Promise 拒绝。

【讨论】:

【参考方案3】:

异步抛出的错误是一个不同的野兽

是的。并且必须不惜一切代价避免它。因此,永远不要将业务代码(包括属性访问等琐碎的事情)放在异步的非承诺回调中。它可以扔!很明显,JSON.parse 可能会失败,当“对象”是 nullundefined 或涉及 getter 时,属性访问可能会抛出,或者循环可能会在本应发生的事情时失败一个数组没有.length

唯一允许作为异步非承诺回调的是 resolvereject(err, res) => if (err) reject(err); else resolve(res); (对于具有多个参数的怪异 API,可能是可变参数版本)。

所以把不好的代码改写成

async getLocation() 
    await new Promise(resolve => setTimeout(resolve, 100));
    throw Error("ffffff");

getLocation() 
    return new Promise(resolve => setTimeout(resolve, 100)).then(res => 
        throw Error("ffffff");
    );

当它是第三方代码让他们修复它时,对您的修复提出上游合并请求,或者如果这些不起作用则放弃该方。

有没有更好的模式来捕捉这个?

好吧,domains(在节点中)本应解决异步(未捕获)异常的非局部性问题,但they didn't work out。也许有一天,拥有更好的母语支持的zones 会取代它们。

【讨论】:

以上是关于如何捕获异步非承诺错误? (对特定错误做出反应)的主要内容,如果未能解决你的问题,请参考以下文章

如何向对消息做出反应的用户添加特定角色

如何解决反应身份验证中的未捕获(承诺中)TypeError?

如何使用特定的 webhook 使机器人对特定频道下的消息做出反应

从全局反应应用程序中的异步函数中捕获错误

对异步和承诺的困惑。反应原生

不能从异步承诺执行器函数中抛出错误