美文网首页js css html
async/await如何优雅捕获错误是该有个结论了

async/await如何优雅捕获错误是该有个结论了

作者: microkof | 来源:发表于2023-02-28 00:00 被阅读0次

前言

async/await如何优雅捕获错误在业界一直存在争论,事实上并没有一个完全得劲的法子,就看相对来讲谁更得劲,而且自己用起来最顺手,那么就用哪一种。今天我们分析一下。

哪些阶段可以捕获错误

  • 对于Ajax请求,捕获错误分3个阶段,依次是:Ajax拦截器、业务代码捕获、全局捕获。

  • 对于来自于第三方库的Promise和非Ajax的Promise,捕获错误分2个阶段:业务代码捕获、全局捕获。

分别解释:

  1. Ajax拦截器是第一层捕获,相当于先行捕获,当然仅限于Ajax请求。拦截器可以拦截掉一批错误,当然必须约定好错误特征,然后也要放行一部分错误,交给业务代码捕获。

  2. 业务代码捕获是本文讨论的重点。

  3. 全局捕获是最后一层捕获,相当于兜底捕获。用法是window.addEventListener('unhandledrejection', fn)。全局捕获主要用于“阻止控制台打印错误”和“统一处理错误”,使用event.preventDefault();可以阻止报错信息出现在控制台,也就是让控制台干净一点,所谓“统一处理错误”就是某些后续处理如果全局统一,则可以一齐处理,比如可以捕获错误日志,上传到服务器。一个成熟的项目是一定应该有一个全局捕获处理的,这个没必要犟。

总之,先行捕获和兜底捕获就处理了很多错误,也就是说业务代码中就不必再写相关捕获代码了,下文集中讨论在业务代码中如何优雅捕获错误。

方案一:try...catch...

ES官方的解决方案,当然也是大家最看不上的方案。

优点

浏览器直接支持,且代码一目了然。

缺点

  1. 原本一行 await 让try...catch...搞成了N行,而且2套大括号,相当于2个块级作用域,真的不优雅。

  2. 接收数据的变量必须在try外部声明,否则没法传递到后续代码。(除非用已经过时的var,然而用var会引起不必要的歧义,所以你根本不应使用var。)

方案二:await-to-js库

伪代码:

var [error, result] = await to(Promise对象);
if (error) {
    alert("xxxxx出错");
    return;
}
var [error, result] = await to(Promise对象);
if (error) {
    alert("ooooo出错");
    return;
}

优点

  1. try...catch是2套大括号,现在await-to-js只需要关注error,所以await-to-js是一套if大括号,而且if可以省掉大括号。

  2. 不存在深层块级作用域,result变量可以轻松传递给后续代码。

缺点

  1. 必须引入一个库,且必须用to()包裹Promise对象。

  2. 将错误和结果包装进一个数组,这种做法有人说觉得很古怪。

方案三:await Promise对象.catch(e=>{...})

这个方案是给Promise对象接一个catch小尾巴。为了完整演示,我加了全局捕获:

      window.addEventListener("unhandledrejection", (e) => {
        e.preventDefault();
        console.log("捕获了", e); // 会执行
      });

      function p() {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            reject(123);
          }, 1000);
        });
      }

      const handle = async () => {
        const result = await p().catch((err) => {
          alert(err);
          return Promise.reject(err);
        });
        console.log(result); // 不会执行
      };
      handle();

要点是catch函数里必须return一个reject的Promise,这样才能阻止代码继续执行。当然,也可以throw new Error(err),都行。

优点:

  1. 全原生。

  2. 不存在变量作用域烦恼。

  3. 行数比await-to-js还少一行(如果if不用语法糖的话)。

缺点:

  1. 必须用全局捕获才能阻止错误出现在控制台,但是我说了,全局捕获是项目标配,所以这个缺点不叫缺点。

  2. 必须继续抛出错误,不过由于await-to-js也至少要写return false,都要占行数,所以平手。

不是方案纯属搞笑:用babel插件给await包裹try...catch...

这类插件还不止一个,随便说一个:https://www.npmjs.com/package/babel-plugin-await-add-trycatch

为什么我说这些插件纯属搞笑呢?

你在编译后给await包裹try...catch...有个卵锤子用?你也不能自定义catch分支的代码,所以唯一的卵用就是不让错误暴露在控制台,针对这点我只想说,插件的开发者们就不知道有全局捕获这个玩意么?

总结

不言而喻,高下立判,最优解就是方案三,也就是catch方案,全原生代码,且无缺点。

如果您还有不同观点,请指出。

相关文章

  • es6 async / await 使用经验总结

    async await使用的注意事项 async await注意 不能捕获Promise抛出的异常,所以我按下面的...

  • node.js 实战:如何优雅的处理异常

    概述 在使用异步的终极解决方案-ES7的async/await同时,如何优雅的处理错误提高代码的兼容性让作为码农的...

  • async和await

    浅谈Async/Await用 async/await 来处理异步 async和await async:声明一个异步...

  • 如何优雅地处理Async/Await的异常?

    译者按: 使用.catch()来捕获所有的异常 原文: Async Await Error Handling in...

  • ES7 中 async await

    处理多个之间相互依赖的请求,使用async和await会更加优雅。async/await规则一、凡是在前面添加了a...

  • async

    async/await特点 async/await更加语义化,async是“异步”的简写,async functi...

  • 'async' call in a function that

    在Swift5.5中使用async/await时,调用async函数的时候,出现了一个错误。 我的代码如下: 原因...

  • Async/await

    async/await是一种用来处理Promise的特殊语法,同时给人的感觉又非常优雅。 Async 函数 我们先...

  • ES6中的好东西

    1 Await/Async 前端的回调时代我没有赶上,我赶上的是await/async时代。await和async...

  • Vue接口调用方式(三)async/await用法

    async/await用法 1. async/await的基本用法 async/await是ES7引入的新语法,可...

网友评论

    本文标题:async/await如何优雅捕获错误是该有个结论了

    本文链接:https://www.haomeiwen.com/subject/xhxmxltx.html