首页新闻动态正文

[南京校区]如何优雅地处理 Async / Await 的异常?【黑马web前端】

更新时间:2019年07月26日 10时53分15秒 来源:黑马程序员论坛

async/await 中的异常处理很让人混乱。尽管有很多种方式来应对async 函数的异常,但是连经验丰富的开发者有时候也会搞错。
假设你有一个叫做run()的异步函数。在本文中,我会描述 3 种方式来处理run()的异常情形: try/catch, Go 语言风格, 函数调用的时候使用 catch()(即run().catch())。 我会跟你解释为什么其实几乎只需要catch()就足够。
try/catch当你第一次使用async/await, 你可能尝试使用try/catch将每一个 async 操作包围起来。如果你await一个被 reject 的 Promise,JavaScript 会抛出一个可以被捕获的错误。
run();async function run() {    try {        await Promise.reject(new Error("Oops!"));    } catch (error) {        error.message; // "Oops!"    }}复制代码try/catch 能够捕获非异步的异常。
run();async function run() {    const v = null;    try {        await Promise.resolve("foo");        v.thisWillThrow;    } catch (error) {        // "TypeError: Cannot read property 'thisWillThrow' of null"        error.message;    }}复制代码所以,只需要将所有的代码逻辑都用 try/catch包围起来就可以搞定?也不完全正确。下面的代码会抛出unhandled promise rejection. await将一个被拒绝的 promise 转换为可捕获的错误,但是 return 不行。
run();async function run() {    try {        // 注意这里是return,不是await        return Promise.reject(new Error("Oops!"));    } catch (error) {        // 代码不会执行到这里    }}复制代码也不可能使用 return await来绕开。
还有一个缺点就是使用了try/catch 之后,就很难用.的语法来进行 Promise 链式组合了。
使用 Go 的语法另一个常见的方式就是使用then()将一个本来需要用catch()来捕获并处理的 Promise 转换为普通的 Promise。然后像 Go 语言中一样,使用if(err)来处理异常。
run();async function throwAnError() {    throw new Error("Oops!");}async function noError() {    return 42;}async function run() {    // The `.then(() => null, err => err)` 来匹配正常/异常的情况。如果正常情况,返回`null`;如果异常,返回`err`    let err = await throwAnError().then(() => null, err => err);    if (err != null) {        err.message; // 'Oops'    }    err = await noError().then(() => null, err => err);    err; // null}复制代码如果你真的想要同时返回 error 和正确的值,你可以完全假装在用 Go 语言。
run();async function throwAnError() {    throw new Error("Oops!");}async function noError() {    return 42;}async function run() {    // The `.then(v => [null, v], err => [err, null])` pattern    // 你可以使用数组解构来匹配err和返回值    let [err, res] = await throwAnError().then(        v => [null, v],        err => [err, null]    );    if (err != null) {        err.message; // 'Oops'    }    err = await noError().then(v => [null, v], err => [err, null]);    err; // null    res; // 42}复制代码使用 Go 语言风格的错误处理并不能摆脱return无法捕获的情况。而且还让整个代码更加的复杂,如果忘记if(err != null),就会出问题。
总的来说,有两大缺点:
  • 代码极度重复,每一个地方都少不了if (err != null) ,真的很累,而且容易漏掉;
  • run()函数中的非异步的错误也无法处理;
总的来说,它并没有比try/catch好多少。
在函数调用的时候使用catch()try/catch 和 Go 语言风格的异常处理都有各自的使用场景,但是处理所有异常最好的方法是在run()函数的后面使用catch(),像这样:run().catch()。换句话说,用一个catch()来处理run函数中的所有错误,而不是针对run里面的每一种情况都去写代码做相应的处理。
run()    .catch(function handleError(err) {        err.message; // Oops!    })    // 在handleError中处理所有的异常    // 如果handleError出错,则退出。    .catch(err => {        process.nextTick(() => {            throw err;        });    });async function run() {    await Promise.reject(new Error("Oops!"));}复制代码记住,async 函数总是返回 promise。只要函数中有异常,Promise 会 reject。而且,如果一个 async 函数返回的是一个 reject 的 Promise,那么这个 Promise 依然会继续被 reject。
run()    .catch(function handleError(err) {        err.message; // Oops!    })    .catch(err => {        process.nextTick(() => {            throw err;        });    });async function run() {    // 注意:这里使用了return,而不是await    return Promise.reject(new Error("Oops!"));}复制代码为什么使用run().catch()而不是将整个run()函数用try/catch包起来呢?我们首先来考虑一个情况:如果try/catch的catch部分有异常,我们应该如何处理呢?只有一个方法:在catch里面接着使用try/catch。所以,run().catch()的模式使得异常处理变得非常简洁。
总结我们最好是全局的有一个 errorHandler 来处理那些没有考虑到的异常,比如使用run().catch(handleError),而不是在run()函数里面所有可能出错的地方加上try/catch。




推荐了解热门学科

java培训 Python人工智能 Web前端培训 PHP培训
区块链培训 影视制作培训 C++培训 产品经理培训
UI设计培训 新媒体培训 产品经理培训 Linux运维
大数据培训 智能机器人软件开发




传智播客是一家致力于培养高素质软件开发人才的科技公司“黑马程序员”是传智播客旗下高端IT教育品牌。自“黑马程序员”成立以来,教学研发团队一直致力于打造精品课程资源,不断在产、学、研3个层面创新自己的执教理念与教学方针,并集中“黑马程序员”的优势力量,针对性地出版了计算机系列教材50多册,制作教学视频数+套,发表各类技术文章数百篇。

传智播客从未停止思考

传智播客副总裁毕向东在2019IT培训行业变革大会提到,“传智播客意识到企业的用人需求已经从初级程序员升级到中高级程序员,具备多领域、多行业项目经验的人才成为企业用人的首选。”

中级程序员和初级程序员的差别在哪里?
项目经验。毕向东表示,“中级程序员和初级程序员最大的差别在于中级程序员比初级程序员多了三四年的工作经验,从而多出了更多的项目经验。“为此,传智播客研究院引进曾在知名IT企业如阿里、IBM就职的高级技术专家,集中研发面向中高级程序员的课程,用以满足企业用人需求,尽快补全IT行业所需的人才缺口。

何为中高级程序员课程?

传智播客进行了定义。中高级程序员课程,是在当前主流的初级程序员课程的基础上,增加多领域多行业的含金量项目,从技术的广度和深度上进行拓展“我们希望用5年的时间,打造上百个高含金量的项目,覆盖主流的32个行业。”传智播客课程研发总监于洋表示。




黑马程序员热门视频教程【点击播放】

Python入门教程完整版(懂中文就能学会) 零起点打开Java世界的大门
C++| 匠心之作 从0到1入门学编程 PHP|零基础入门开发者编程核心技术
Web前端入门教程_Web前端html+css+JavaScript 软件测试入门到精通


在线咨询 我要报名
和我们在线交谈!