缘由

JS中async/await异步调用,只能通过try-catch吗?

你想听的故事:

作为一个合格的全栈搬砖工,那必须文武双全,前后必备。遂吾日三省吾身,偶发觉前端长时间不写有些落下,便抽用了摸鱼的时间,检查一下前端小老弟的代码。

不查不知道,一查吓一跳。乍一看小老弟代码清新脱俗,特别规整,但存重大的隐患:



不知道大家看没看出,里面竟然没有异常捕获,完全逻辑代码一把嗦。可能有小伙伴说,我平时也这么写,也没遇到什么大坑,大不了页面报错呗,改就完了。

话虽如此,有坑没趟上,不代表永远顺风输水,如果不进行异常捕获,那么页面逻辑可能会因为此处异常戛然而止,导致后续业务无法正常执行

光描述可能小伙伴还是没有代码上概念,下面举一个例子便一目了然

举个栗子

有个页面,需要展示会员信息和推荐商品,前端页面需要调用后端接口并把两者赋值,显示到页面上

正常情况:调异步接口正常返回

此处模拟前端调用后端两个接口,分别获取会员信息商品信息两者互不影响,并打印。

小伙伴们可以看到,和我们预想一样,没有趟坑,非常顺利,没有任何问题

// 实例模拟页面初始化调用两个异步接口,并打印成功返回的数据
const getMember = async () => {
return new Promise((resolve, reject) => {
// 模拟接口获取会员数据
setTimeout(() => {
// 成功返回
resolve(
{
name: '张三',
age: 18
}
)
}, 1000)
})
} const getGoods = async () => {
return new Promise((resolve, reject) => {
// 模拟接口获取商品数据
setTimeout(() => {
// 成功返回
resolve(
[{
name: '面包',
price: 5
},{
name: '牛奶',
price: 6
}]
)
}, 2000)
})
} const init = async () => {
const member = await getMember();
console.log("会员:", member) const goods = await getGoods();
console.log("商品:", JSON.stringify(goods))
} init(); // 打印结果
// 会员: { name: '张三', age: 18 }
// 商品: [{"name":"面包","price":5},{"name":"牛奶","price":6}]


异常情况:调异步接口且未捕获异常

此处同上模拟前端调用后端两个接口,此时会员信息接口出现问题异常,商品信息接口正常

小伙伴们可以看到,此时就掉入没有捕获异常的的坑了,非常遗憾,后续牵连接口一并因错误戛然而止,出错连坐!

// 实例模拟页面初始化调用两个异步接口,第一个获取会员信息异常,第二个商品数据正常
const getMember = async () => {
return new Promise((resolve, reject) => {
// 模拟获取会员数据接口异常
setTimeout(() => {
// 成功返回
reject(new Error('会员接口异常'))
}, 1000)
})
} const getGoods = async () => {
return new Promise((resolve, reject) => {
// 模拟接口获取商品数据
setTimeout(() => {
// 成功返回
resolve(
[{
name: '面包',
price: 5
},{
name: '牛奶',
price: 6
}]
)
}, 2000)
})
} const init = async () => {
const member = await getMember();
console.log("会员:", member) const goods = await getGoods();
console.log("商品:", JSON.stringify(goods))
} init(); // 打印结果
// 直接报异常,并且后面正常的商品接口console.log都没有打印内容

这种情况就导致,后续无关接口也无法正常返回,从而页面可能直接崩溃

综上案例,所以异常必须捕获,而且要捕获的漂亮


主要目标

实现重点

async/await异常捕获方法

正文

目标解析

async/await异常捕获方法

方法一:try-catch

任何异步调用全部一把嗦,全部套上try-catch壳

还是以上述内容为案例,将调用接口加入try-catch后,第一个接口异常后,后续接口不受影响

try{
// 加入try-catch异常捕获
const member = await getMember();
console.log("会员:", member)
}catch (e){
console.error("会员接口异常:", e)
}
// 完整代码
const getMember = async () => {
return new Promise((resolve, reject) => {
// 模拟获取会员数据接口异常
setTimeout(() => {
// 成功返回
reject(new Error('会员接口异常'))
}, 1000)
})
} const getGoods = async () => {
return new Promise((resolve, reject) => {
// 模拟接口获取商品数据
setTimeout(() => {
// 成功返回
resolve(
[{
name: '面包',
price: 5
},{
name: '牛奶',
price: 6
}]
)
}, 2000)
})
} const init = async () => {
try{
// 加入try-catch异常捕获
const member = await getMember();
console.log("会员:", member)
}catch (e){
console.error("会员接口异常:", e)
} try{
// 加入try-catch异常捕获
const goods = await getGoods();
console.log("商品:", JSON.stringify(goods))
}catch (e){
console.error("商品异常:", e)
}
} init(); // 打印结果
// 会员接口异常:xxxxx
// 商品: [{"name":"面包","price":5},{"name":"牛奶","price":6}]

try-catch的弊端

接口少还好说,无脑加;接口多就会出现大批的try-catch军团,代码冗余并且十分混乱,阅读十分吃力!


方法二:使用 Promise 处理

解释一下:await 命令后面是一个 Promise 对象,直接可以使用.catch来捕获异常

// 直接后面跟着.catch
const member = await getMember().catch((err) => {console.error("会员接口异常:", err)});
// 完整代码
//
const getMember = async () => {
return new Promise((resolve, reject) => {
// 模拟获取会员数据接口异常
setTimeout(() => {
// 成功返回
reject(new Error('会员接口异常'))
}, 1000)
})
} const getGoods = async () => {
return new Promise((resolve, reject) => {
// 模拟接口获取商品数据
setTimeout(() => {
// 成功返回
resolve(
[{
name: '面包',
price: 5
},{
name: '牛奶',
price: 6
}]
)
}, 2000)
})
} const init = async () => {
// 加入.catch异常捕获
const member = await getMember().catch((err) => {console.error("会员接口异常:", err)});
if(member){
console.log("会员:", member)
// 处理会员业务逻辑...
} // 加入.catch异常捕获
const goods = await getGoods().catch((err) => {console.error("商品接口异常:", err)});
if(goods){
console.log("商品:", JSON.stringify(goods));
// 处理商品业务逻辑...
} } init(); // 打印结果
// 会员接口异常:xxxxx
// 商品: [{"name":"面包","price":5},{"name":"牛奶","price":6}]

方法三:使用 await-to-js插件库

  • await-to-js是什么

await-to-js 是一个辅助开发者处理异步错误的库

  • await-to-js怎么下
# npm安装
npm i await-to-js --save
# yarn安装
yarn add await-to-js
  • await-to-js怎么写
import to from 'await-to-js'
const init = async () => {
const [err, data] = await to(getMember())
if (err){
console.error("会员接口异常:", err)
return
}
console.log("会员:", data) const [err1, data1] = await to(getGoods())
if (err1){
console.error("商品接口异常:", err1)
return
}
console.log("商品:", JSON.stringify(data1))
}
// 完整代码
import to from 'await-to-js'
const getMember = async () => {
return new Promise((resolve, reject) => {
// 模拟获取会员数据接口异常
setTimeout(() => {
// 成功返回
reject(new Error('会员接口异常'))
}, 1000)
})
} const getGoods = async () => {
return new Promise((resolve, reject) => {
// 模拟接口获取商品数据
setTimeout(() => {
// 成功返回
resolve(
[{
name: '面包',
price: 5
},{
name: '牛奶',
price: 6
}]
)
}, 2000)
})
} const init = async () => {
const [err, data] = await to(getMember())
if (err){
console.error("会员接口异常:", err)
return
}
console.log("会员:", data) const [err1, data1] = await to(getGoods())
if (err1){
console.error("商品接口异常:", err1)
return
}
console.log("商品:", JSON.stringify(data1))
} init(); // 打印结果
// 会员接口异常:xxxxx
// 商品: [{"name":"面包","price":5},{"name":"牛奶","price":6}]
  • await-to-js源码分析
/**
* @param { Promise } promise
* @param { Object= } errorExt - Additional Information you can pass to the err object
* @return { Promise }
*/
export function to<T, U = Error>(
promise: Promise<T>,
errorExt?: object
): Promise<[U, undefined] | [null, T]> {
return promise
.then<[null, T]>((data: T) => [null, data])
.catch<[U, undefined]>((err: U) => {
if (errorExt) {
const parsedError = Object.assign({}, err, errorExt)
return [parsedError, undefined]
} return [err, undefined]
})
} export default to

分析一下:

to方法入参是promise对象和自定义异常

如果没有异常则直接返回[null, data],数组第一项是异常信息为null,第二项为正常数据

如果捕获异常在catch中组装[err, undefined] 错误信息,数组第一项是异常信息为err,第二项数据为null


总结

本文通过async/await为切入点,介绍三种异步调用处理异常的方法:分别是try-catch、promise处理、await-to-js插件库处理。

希望小伙伴能学以致用,精进代码的同时,也让别人看我们代码时,变得易读好上手,人如其码!


猜你想问

如何与狗哥联系进行探讨

关注公众号【JavaDog程序狗】

公众号回复【入群】或者【加入】,便可成为【程序员学习交流摸鱼群】的一员,问题随便问,牛逼随便吹,目前群内已有超过200+个小伙伴啦,只能拉人入群啦!!!

2.踩踩狗哥博客

javadog.net

大家可以在里面留言,随意发挥,有问必答


猜你喜欢

文章推荐

【规范】看看人家Git提交描述,那叫一个规矩

【工具】用nvm管理nodejs版本切换,真香!

【苹果】SpringBoot监听Iphone15邮件提醒,Selenium+Python自动化抢购脚本

【项目实战】SpringBoot+uniapp+uview2打造H5+小程序+APP入门学习的聊天小项目

【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序

【模块分层】还不会SpringBoot项目模块分层?来这手把手教你!

【ChatGPT】手摸手,带你玩转ChatGPT

【ChatGPT】SpringBoot+uniapp+uview2对接OpenAI,带你开发玩转ChatGPT


【JS】await异常捕获,这样做才完美的更多相关文章

  1. js的异常捕获

    try{ ...some code... }catch(e){ ...some code... //处理错误 throw(e.name); //抛出异常 }finally{<BR> // ...

  2. Js全局异常捕获

    重新window.onerror方法就行了 window.onerror = handleError function handleError(msg,url,l) { var txt="T ...

  3. 异常捕获 崩溃 Bugly ACRC 简介 总结 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  4. 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获

    项目开发中的一些注意事项以及技巧总结   1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...

  5. atitit.js浏览器环境下的全局异常捕获

    atitit.js浏览器环境下的全局异常捕获 window.onerror = function(errorMessage, scriptURI, lineNumber) { var s= JSON. ...

  6. JS异常捕获和抛出

    try...catch 用来异常捕获(主要适用于IE5以上内核的浏览器,也是最常用的异常捕获方式) 使用onerror时间捕获异常,这种捕获方式是比较古老的一中方式,目前一些主流的浏览器暂不支持这种 ...

  7. JavaScript异常捕获

    理论准备 ★   异常捕获 △ 异常:当JavaScript引擎执行JavaScript代码时,发生了错误,导致程序停止运行: △ 异常抛出:当异常产生,并且这个异常生成一个错误信息: △ 异常捕获: ...

  8. iOS异常捕获

    文章目录 一. 系统Crash 二. 处理signal 下面是一些信号说明 关键点注意 三. 实战 四. Crash Callstack分析 – 进⼀一步分析 五. demo地址 六. 参考文献 前言 ...

  9. T-SQL编程中的异常处理-异常捕获(catch)与抛出异常(throw)

    本文出处: http://www.cnblogs.com/wy123/p/6743515.html T-SQL编程与应用程序一样,都有异常处理机制,比如异常的捕获与异常的抛出,本文简单介绍异常捕获与异 ...

  10. Spring AOP异常捕获原理

    Spring AOP异常捕获原理:        被拦截的方法,须显式的抛出异常,且不能做任何处理, 这样AOP才能捕获到方法中的异常,进而进行回滚.        换句话说,就是在Service层的 ...

随机推荐

  1. mysql 必知必会整理—sql 简单语句[二]

    前言 简单整理一下sql 排序与过滤. 正文 在这里需要创建一下一个数据库实例. 为了方便直接用docker 创建一下啊,方便简洁. https://hub.docker.com/_/mysql 按照 ...

  2. 重新点亮linux 命令树————网络故障排除[十一五]

    前言 简单整理一下网络故障不可达命令. 正文 ping 是否能ping traceroute 追踪路由跳转 mtr 检查数据包是否丢失 nslookup telnet 端口是否可达 tcpdump 能 ...

  3. Redis 的并发竞争问题是什么?如何解决这个问题?了解 redis 事务的 CAS 方案吗?

    面试官心理分析 这个也是线上非常常见的一个问题,就是多客户端同时并发写一个 key,可能本来应该先到的数据后到了,导致数据版本错了:或者是多客户端同时获取一个 key,修改值之后再写回去,只要顺序错了 ...

  4. 《c#高级编程》第3章C#3.0中的更改(五)——扩展方法

    C#扩展方法是一种语法,可以为已有的类添加新的实例方法,而无需修改原来的类定义.它的语法形式为: ```csharppublic static void MyExtensionMethod(this ...

  5. 【Oracle】使用PL/SQL快速查询出1-9数字

    [Oracle]使用PL/SQL快速查询出1-9数字 简单来说,直接Recursive WITH Clauses 在Oracle 里面就直接使用WITH result(参数)即可 WITH resul ...

  6. 剑指offer21(Java)-调整数组顺序使奇数位于偶数前面(简单)

    题目: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分. 示例: 输入:nums = [1,2,3,4]输出:[1,3,2,4] 注:[ ...

  7. python:在cmd中输入pip install pandas 显示‘pip’不是内部或外部命令,也不是可运行的程序 或批处理文件解决办法

    1.首先找到自己文件夹中python的安装位置,一定要在Scripts文件夹下,可以看到pip文件,复制这时候的路径 2.使用快捷键  "win +R"打开cmd窗口,首先进入自己 ...

  8. 19_非单文件名组件中VueComponent构造函数&重要的内置关系

    总结: 关于VueComponent:     1.school组件本质上是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的.     2.我们只需要写&l ...

  9. 力扣202(java&python)-快乐数(简单)

    题目: 编写一个算法来判断一个数 n 是不是快乐数. 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和.然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终 ...

  10. CF1857B Maximum Rounding 题解

    题目描述 给定一个自然数 \(n\),可以对任意一位进行四舍五入,可以进行任意次,求能得到的最大数.(这里的 \(n\) 没有前导零) 思路 首先我们发现,如果我们将其中一位进位了,那后面的所有位都会 ...