当前位置: 首页 > news >正文

js异常处理方案

文章目录

  • 异常处理方案
  • 同步代码的异常处理
  • Promise 的异常处理
  • async await 的异常处理

感谢阅读,觉得有帮助可以点点关注点点赞,谢谢!

异常处理方案

在JS开发中,处理异常包括两步:先抛出异常,然后捕获异常。
为什么要做异常处理
异常处理非常重要,至少有以下几个原因:

1.防止程序报错甚至停止运行:当代码执行过程中发生错误或异常时,如果没有适当的异常处理机制,程序可能会报错、停止运行,甚至崩溃。通过处理异常,我们可以捕获错误并采取适当的措施避免系统报错。
2.错误排查和调试:异常处理有助于定位和排查错误。可以通过捕获异常并输出相关信息,比如打印日志、错误上报、跟踪堆栈等等,以便快速定位问题所在,并进行调试和修复。
3.提高代码健壮性和可靠性:可以采取适当的措施处理潜在的异常情况,从而减少程序出错的可能性。
4.提升用户体验:通过兜底、容错、容灾等异常处理方案,可以向用户提供有效的错误信息提示,而不是让用户界面无响应甚至白屏。

抛出异常
抛出异常的使用场景举例:
我们经常会封装一些工具函数,这些函数可能给自己用,也可能给外部团队用。
在函数内部,如果不符合预期的业务逻辑,或者遇到异常情况时,很多人的写法是直接 return,不往下执行了。但是 return 的写法存在一个很大的弊端:调用者不知道是因为函数内部没有正常执行,还是执行的返回结果就是一个undefined。return 的写法只是规避了问题,没有解决问题。建议的做法是:我们需要手动抛出异常

捕获异常
如果只是抛出异常,而不捕获异常的话,是比较危险的。这意味着当前任务立即终止,不再执行(当然,后续的其他任务会正常执行)。此外,这个异常信息会层层往上,抛给上层的调用者。如果一直未被捕获,则最终会抛给浏览器,浏览器控制台就会报错。

接下来,我们看一下不同代码场景下的异常处理方案。

上报异常
如果有必要的话,你可以把异常信息和日志,上报给监控服务器,然后集中分析。我每天上班第一件事,就是打开监控系统,看错误日志,然后对症下药解决问题

同步代码的异常处理

通过 throw 抛出异常
我们可以通过 throw关键字,抛出一个用户自定义的异常。当代码执行时遇到 throw 语句时,当前函数会停止停止,即:当前函数 throw 后面的代码不会再执行。

throw 意思是,告诉调用者,当前被调用的函数报错了,调用者接下来需要捕获异常或者修改代码逻辑。

可以在 throw 的后面添加表达式或者数据类型,将添加的内容抛出去。数据类型可以是:number、string、boolean、对象等。

代码举例:

function sum(num1, num2) {if (typeof num1 !== "number") {throw "type error: num1传入的类型有问题, 必须是number类型"}if (typeof num2 !== "number") {throw "type error: num2传入的类型有问题, 必须是number类型"}return num1 + num2
}sum('a', 'b');

打印结果:
在这里插入图片描述
当然,我们还可以 throw一个封装好的对象。比如:

class myError {constructor(errCode, errMsg) {this.errCode = errMsg;this.errMsg = errMsg;}
}function foo() {throw new myError(-1, 'not login');
}foo();

上面这种写法比较麻烦,一般不这么写。其实,JS中已经内置了 Error 类,专门用于生成错误信息。
Error 类
JS内置的 Error 类非常好用。

代码举例:

function foo() {throw new Error('not login');
}foo();

打印结果:
在这里插入图片描述
上面的打印结果可以看到,通过 Error 抛出来的错误,不仅可以看到报错信息,还可以看到调用栈,便于快速定位问题所在。非常方便。

通过 try catch 捕获异常
同步代码,只抛出异常,不捕获异常的代码举例:

function foo() {throw new Error('not login');
}foo();
// 当前任务立即终止,不再执行;下面这行代码和 foo() 都在同一个 同步任务 中
console.log('qianguyihao');

打印结果:
在这里插入图片描述
可以看到,最后一行的 log 并没有执行。

我们可以使用 try catch 抛出异常, 对上述代码进行改进。代码举例:

function foo() {throw new Error('not login');
}// 通过 try catch 手动捕获异常
try {foo();
} catch (err) {console.log(err);
}// 当前任务的后续代码会继续执行
console.log('qianguyihao');

打印结果:
在这里插入图片描述
通过 try catch finally 捕获异常
如果有些代码必须要执行,我们可以放到 finally 里。

不管是否遇到异常,finally的代码一定会执行。
如果 try 和 finally 中都有返回值,那么会使用finally中的返回值。

代码举例:

function foo() {throw new Error('not login');
}// 通过 try catch 捕获异常
try {foo();
} catch (err) {console.log(err);
} finally {console.log("finally")
}// 后续代码会继续执行
console.log('qianguyihao');

try catch 只能捕获同步代码的异常
try catch只能捕获同步代码里的异常,而 Promise.reject() 是异步代码。

原因是:当异步函数抛出异常时,对于宏任务而言,执行函数时已经将该函数推入栈,此时并不在 try-catch 所在的栈,所以 try-catch 并不能捕获到错误。对于微任务而言(比如 promise)promise 的构造函数的异常只能被自带的 reject 也就是.catch 函数捕获到。

使用 window.onerror 监听未被捕获的代码异常
如果JS代码抛出了异常但没有进行捕获,我们可以使用 JS 自带的 window.onerror 事件监听到这些错误。
代码举例:

// 监听同步代码的异常
window.onerror = (event) => {console.error('onerror 监听到未被捕获的异常:', event)
};function foo1() {throw new Error('not login');
}function foo2() {throw new Error('network error');
}foo1();
foo2();

打印结果:
在这里插入图片描述

Promise 的异常处理

reject() 会自动抛出异常
在使用 Promise 时,当我们调用了 reject() 之后,系统会自动抛出异常,不需要我们手动抛出异常。这是 Promise的内部机制。但是我们需要手动捕获异常。

当 Promise 进入 rejected状态之后,会触发 catch()方法的执行,捕获异常。此时,成功完成了Promise异常处理的闭环。

在then() 中抛出异常(重要)
当then()方法传入的回调函数中,如果遇到异常或者手动抛出异常,那么,then()所返回的新的 Promise 会进入rejected 状态,进而触发新Promise 的 catch() 方法的执行,做异常捕获。

场景1:在then()方法传入的回调函数中,如果代码在执行时遇到异常,系统会自动抛出异常。此时我们需要在 catch() 里手动捕获异常,否则会报错。

自动抛出异常的代码举例:(由于没有捕获异常,所以会报错)

const myPromise = new Promise((resolve, reject) => {resolve('qianguyihao1 fulfilled');
});myPromise.then(res => {console.log('res1:', res);// 显然,person 并没有 forEach()方法。所以,代码在执行时,会遇到异常。const person = { name: 'vae' };person.forEach(item => {console.log('item:', item);})// 这行代码不会执行,因为上面的代码报错了console.log('qianguyihao2');
}).then(res => {console.log('res2:', res);
})// 定时器里的代码正常执行
setTimeout(() => {console.log('qianguyihao3');
}, 100)

运行结果:
在这里插入图片描述
代码改进:(代码在执行时遇到异常,此时我们捕获异常,所以系统不会报错,这才是推荐的写法)

const myPromise = new Promise((resolve, reject) => {resolve('qianguyihao1 fulfilled');
});myPromise.then(res => {console.log('res1:', res);// 显然,person 并没有 forEach()方法。所以,代码在执行时,会遇到异常。const person = { name: 'vae' };person.forEach(item => {console.log('item:', item);})// 这行代码不会执行,因为上面的代码报错了console.log('qianguyihao2');
}).then(res => {console.log('res2:', res);
}).catch(err => {// 在 catch()方法传入的会调函数里,捕获异常console.log('err2:', err);
})// 定时器里的代码正常执行
setTimeout(() => {console.log('qianguyihao3');
}, 100)

打印结果
在这里插入图片描述
场景2:在then()方法传入的回调函数中,如果我们手动抛出异常,此时我们需要在 catch() 里手动捕获异常,否则会报错。

代码举例:(手动抛出异常,未捕获,所以会报错)

const myPromise = new Promise((resolve, reject) => {resolve('qianguyihao fulfilled 1');
});myPromise.then(res => {console.log('res1:', res);// 手动抛出异常throw new Error('qianguyihao rejected 2')
}).then(res => {console.log('res2:', res);
})// 定时器里的代码正常执行
setTimeout(() => {console.log('qianguyihao3');
}, 100)

打印结果:
在这里插入图片描述
代码改进:(代码在执行时遇到异常,此时我们捕获异常,所以系统不会报错,这才是推荐的写法)

const myPromise = new Promise((resolve, reject) => {resolve('qianguyihao fulfilled 1');
});myPromise.then(res => {console.log('res1:', res);// 手动抛出异常throw new Error('qianguyihao rejected 2')
}).then(res => {console.log('res2:', res);
}, (err) => {console.log('err2:', err);
})// 定时器里的代码正常执行
setTimeout(() => {console.log('qianguyihao3');
}, 100)

打印结果:
在这里插入图片描述
使用 unhandledrejection 事件监听未被捕获的Promise异常
如果Promise抛出了异常但没有进行捕获,我们可以使用JS自带的 unhandledrejection 事件监听到这些错误。这个事件非常有用,尤其是当我们需要集中做日志收集时,屡试不爽。这个事件只能用于监听 Promise 中的异常,不能用于其他同步代码的异常。

先来看下面这行代码:

const myPromise = new Promise((resolve, reject) => {console.log('qianguyihao1');reject('not login');console.log('qianguyihao2');
})

打印结果:
在这里插入图片描述
上面的代码抛出了异常,但没有捕获异常,所以我们可以用 unhandledrejection 事件监听到。代码举例:

// 监听未被捕获的 Promise 异常
window.addEventListener('unhandledrejection', (event) => {console.error(`unhandledrejection 监听到异常,写法1: ${event.reason}`)
});window.onunhandledrejection = event => {console.error(`unhandledrejection 监听到异常,写法2: ${event.reason}`);
};window.onerror = (event) => {console.error('onerror 监听到异常:', event);
};const promise1 = new Promise((resolve, reject) => {reject('not login');
})const promise2 = new Promise((resolve, reject) => {throw new Error('network error');resolve();
})

打印结果:
在这里插入图片描述
可以看到,promise1 和 Promise2 的异常,都被 unhandledrejection 事件收集到了。

代码举例2:

window.addEventListener('unhandledrejection', (event) => {console.error(`unhandledrejection 监听到异常: ${event.reason}`)
});window.onerror = (event) => {console.error('onerror 监听到异常:', event);
};const myPromise = new Promise((resolve, reject) => {setTimeout(() => {throw new Error('not login');resolve();}, 100);
})

打印结果:
在这里插入图片描述
上面的代码中,unhandledrejection 无法监听异常,因为定时器里的代码属于宏任务。

resolve()之后,再报错无效
代码举例:

const myPromise = new Promise((resolve, reject) => {resolve('fulfilled');throw new Error("自定义错误");
});myPromise.then(res => {console.log("res", res);return res + 1;
}).catch(err => {console.log("err:", err);
});

打印结果:

res fulfilled

上方代码中,第3行的异常代码相当于没写。因为 resolve()之后,Promise的状态会立即进入 fulfilled,然后走到 then(),状态不可逆。

async await 的异常处理

捕获异常
代码举例:

function requestData1() {return new Promise((resolve, reject) => {reject('任务1失败');})
}function requestData2() {return new Promise((resolve, reject) => {resolve('任务2成功');})
}async function getData() {// requestData1 在执行时,遇到异常await requestData1();/*由于上面的代码在执行是遇到异常,所以,这里虽然什么都没写,底层默认写了如下代码:return Promise.reject('任务1失败');*/// 下面这两行代码不会再执行了,因为上面的代码遇到了异常console.log('qianguyihao1');await requestData2();
}getData();// 【注意】定时器里的代码会正常实行,因为它在另外一个宏任务里,不在上面的微任务里
setTimeout(() => {console.log('qianguyihao2');
}, 100)

打印结果:
在这里插入图片描述
所以,为了避免上述问题,我们还需要手动捕获异常。我们捕获到异常之后,这个异常就不会继续网上抛了,更不会抛给浏览器。

感谢阅读,觉得有帮助可以点点关注点点赞,谢谢!

相关文章:

js异常处理方案

文章目录 异常处理方案同步代码的异常处理Promise 的异常处理async await 的异常处理 感谢阅读,觉得有帮助可以点点关注点点赞,谢谢! 异常处理方案 在JS开发中,处理异常包括两步:先抛出异常,然后捕获异常。…...

C++文件路径处理2 - 路径拼接路径解析

1. 关键词2. filesystem.h3. filepath.cpp6. 测试代码7. 运行结果8. 源码地址 1. 关键词 关键词: C 文件路径处理 路径拼接 获取父目录的路径 获取文件名 获取拓展名 跨平台 应用场景: 路径的拼接路径的解析 2. filesystem.h #pragma once#include…...

数据结构5---矩阵和广义表

一、矩阵的压缩存储 特殊矩阵:矩阵中很多值相同的元素并且它们的分布有一定的规律。 稀疏矩阵:矩阵中有很多零元素。压缩存储的基本思想是: (1)为多个值相同的元素只分配一个存储空间; (2)对零元素不分配存储空间。 1、特殊矩阵的压缩存储 (1)对称矩…...

jquery使用infinitescroll无线滚动+自定义翻页

jquery版本 jquery-1.8.3.js infinitescroll版本 2.0.0 如果infinitescroll版本最新的jquery版本也要用新的 接口用nodejs jquery.infinitescroll.js官网地址 前端代码《接口返回JSON数据》 <!DOCTYPE html> <html lang"en"> <head><meta cha…...

【漏洞复现】锐捷统一上网行为管理与审计系统——远程命令执行漏洞

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 锐捷统一上网行为管理与审计系统naborTable/static_convert.php…...

通义灵码上线 Visual Studio 插件市场啦!

通义灵码&#xff0c;是阿里云出品的一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码优化、注释生成、代码解释、研发智能问答、异常报错排查等能力&#xff0c;提供代码智能生成、研发智能问答能力。 通义灵…...

GESP 四级急救包(2):客观题真题集

客观题真题集 一、选择题1. 真题梳理2. 真题答案3. 重难点点播(1) 指针和地址(2) 时间复杂度 二、判断题1. 真题梳理2. 真题答案 一、选择题 1. 真题梳理 若函数声明为 void f(int &a, int b, const int &c)&#xff0c;且在主函数内已经声明了 x , y , z x,y,z x,y,…...

VERYCLOUD睿鸿股份确认参展2024年ChinaJoy BTOB商务洽谈馆,期待与你相聚

作为在全球数字娱乐领域兼具知名度与影响力的年度盛会&#xff0c;2024年第二十一届ChinaJoy将于7月26日至7月29日在上海新国际博览中心盛大召开&#xff0c;本届展会主题为&#xff1a;初心“游”在&#xff0c;精彩无限&#xff01;&#xff08;Stay True, Game On.&#xff…...

Java面试题:讨论Spring框架的核心组件,如IoC容器、AOP、事务管理等

Spring框架是一个功能强大且灵活的Java企业级应用开发框架&#xff0c;其核心组件包括以下几个主要部分&#xff1a; 1. IoC容器&#xff08;Inversion of Control Container&#xff09; IoC容器是Spring框架的核心部分&#xff0c;用于管理应用程序的依赖注入&#xff08;D…...

【方案】基于5G智慧工业园区解决方案(PPT原件)

5G智慧工业园区整体解决方案旨在通过集成5G通信技术、物联网、大数据和云计算等先进技术&#xff0c;实现园区的智能化、高效化和绿色化。 该方案首先构建高速、稳定的5G网络&#xff0c;确保园区内设备、人员与物流的实时连接和高效沟通。其次&#xff0c;通过工业物联网技术&…...

使用System.currentTimeMillis获取当前时间

使用System.currentTimeMillis获取当前时间 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们来探讨Java中如何使用System.currentTimeMillis()方法来获取…...

手机远程控制另一台手机的全新使用教程(安卓版)

看完这篇文章&#xff0c;你可以了解到安卓手机如何远程控制安卓手机&#xff0c;以及苹果手机如何远程控制安卓手机。 如果想要用安卓手机远程管控苹果手机&#xff0c;或者苹果手机远程管控另一台苹果手机&#xff0c;请点击查看视频《手机远程管控另一台手机的全新使用教程…...

商城积分系统的代码实现(上)-- 积分账户及收支记录

一、背景 上一系列文章&#xff0c;我们说了积分的数模设计及接口设计&#xff0c;接下里&#xff0c;我们将梳理一下具体的代码实现。 使用的语言的java&#xff0c;基本框架是spring-boot&#xff0c;持久化框架则是Jpa。 使用到的技术点有&#xff1a; 分布式锁&#xf…...

【C++进阶9】异常

一、C语言传统的处理错误的方式 终止程序&#xff0c;如assert 如发生内存错误&#xff0c;除0错误时就会终止程序返回错误码 需要程序员自己去查找对应的错误 z如系统的很多库的接口函数都是通 过把错误码放到errno中&#xff0c;表示错误 二、C异常概念 异常&#xff1a;函…...

RecyclerVIew->加速再减速的RecyclerVIew平滑对齐工具类SnapHelper

XML文件 ItemView的XML文件R.layout.shape_item_view <?xml version"1.0" encoding"utf-8"?> <FrameLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"100dp"android:layout_heig…...

突破SaaS产品运营困境:多渠道运营如何集中管理?

随着数字化时代的到来&#xff0c;SaaS&#xff08;软件即服务&#xff09;产品已成为企业日常运营不可或缺的工具。然而&#xff0c;在竞争激烈的市场环境下&#xff0c;SaaS产品运营越来越重视多渠道、多平台布局&#xff0c;以更广泛地触及潜在用户&#xff0c;然而&#xf…...

智能语音热水器:置入NRK3301离线语音识别ic 迈向智能家居新时代

一、热水器语音识别芯片开发背景 在科技的今天&#xff0c;人们对于生活品质的追求已不仅仅满足于基本的物质需求&#xff0c;更渴望通过智能技术让生活变得更加便捷、舒适。热水器作为家庭生活中不可或缺的一部分&#xff0c;其智能化转型势在必行。 在传统热水器使用中&#…...

Redis集群部署合集

目录 一. 原理简述 二. 集群配置​​​​​​​ 2.1 环境准备 2.2 编译安装一个redis 2.3 创建集群 2.4 写入数据测试 实验一&#xff1a; 实验二&#xff1a; 实验三&#xff1a; 实验四&#xff1a; 添加节点 自动分配槽位 提升节点为master&#xff1a; 实验…...

【HDFS】关于Hadoop的IPC.Client类的一些整理

org.apache.hadoop.ipc.Client 类是IPC服务的一个客户端。 IPC请求把一个Writable对象当做参数,返回一个Writable对象当做结果value。 一个IPC服务运行在某个端口上,并且由参数class和value class定义。 Router里的IPC.Client对象就两个 有这样一个类:ClientCache 看名字就…...

Swoole v6 能否让 PHP 再次伟大?

现状 传统的 PHP-FPM 也是多进程模型的的运行方式&#xff0c;但每个进程只能处理完当前请求&#xff0c;才能接收下一个请求。而且对于 PHP 脚本来说&#xff0c;只是接收请求和响应请求&#xff0c;并不参与网络通信。对数据库资源的操作&#xff0c;也是一次请求一次有效&am…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

API网关Kong的鉴权与限流:高并发场景下的核心实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中&#xff0c;API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关&#xff0c;Kong凭借其插件化架构…...

数据库——redis

一、Redis 介绍 1. 概述 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的内存键值数据库系统&#xff0c;具有以下核心特点&#xff1a; 内存存储架构&#xff1a;数据主要存储在内存中&#xff0c;提供微秒级的读写响应 多数据结构支持&…...