第三部分:进阶概念 9.错误处理 --[JavaScript 新手村:开启编程之旅的第一步]

news2024/12/12 23:36:11

在JavaScript中,错误处理是确保应用程序稳定性和用户体验的重要部分。JavaScript提供了几种机制来捕获和处理运行时错误(异常)。以下是几种常见的错误处理方式:

1. try...catch 语句

try...catch 语句是JavaScript中处理错误和异常的主要方式。它允许你尝试执行一段代码,并指定如果发生错误该如何处理。以下是三个使用 try...catch 语句的示例,展示了不同场景下的应用。

示例 1:基本用法

在这个简单的例子中,我们尝试访问一个未定义的对象属性,这会导致抛出一个 TypeError。我们使用 try...catch 来捕获并处理这个错误。

try {
  // 尝试执行可能抛出异常的代码
  let result = undefinedObject.property;
} catch (error) {
  // 捕获并处理错误
  console.error("An error occurred:", error.name, error.message);
} finally {
  // 可选:无论是否发生错误都会执行的代码
  console.log("This will run no matter what.");
}

输出结果将会是:

An error occurred: ReferenceError undefinedObject is not defined
This will run no matter what.

在这里插入图片描述

示例 2:手动抛出错误

有时候你可能希望在特定条件下手动抛出错误。例如,在验证用户输入时,如果输入不符合预期,可以抛出一个自定义错误。

function validateAge(age) {
  if (age < 0 || age > 120) {
    throw new Error("Invalid age. Please enter a value between 0 and 120.");
  }
  return "Age is valid.";
}

try {
  console.log(validateAge(-5));
} catch (error) {
  console.error("Validation failed:", error.message);
}

输出结果将会是:

Validation failed: Invalid age. Please enter a value between 0 and 120.

在这里插入图片描述

示例 3:异步操作中的错误处理

当处理异步操作(如网络请求)时,try...catch 结合 async/await 是一种优雅的方式来进行错误处理。下面的例子展示了如何处理一个可能会失败的 fetch 请求。

async function fetchData(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    console.log("Data fetched successfully:", data);
  } catch (error) {
    console.error("Fetch failed:", error.message);
  }
}

// 调用函数并传入一个有效的或无效的URL来测试
fetchData('https://api.example.com/data');

在这里插入图片描述

假设提供的 URL 是无效的或者服务器返回了一个非200的状态码,输出结果将会是:

Fetch failed: HTTP error! status: 404

如果 URL 是有效的并且服务器返回了成功的响应,那么将会输出:

Data fetched successfully: { /* 数据对象 */ }

通过这些示例,你可以看到 try...catch 语句不仅可以用于同步代码,也可以很好地处理异步操作中的错误。此外,它还支持手动抛出自定义错误,以便更精确地控制应用程序的行为和逻辑。

2. 抛出错误 throw

throw 语句用于手动抛出一个异常,这可以是任何类型的表达式(如字符串、数字、布尔值或对象),但最常见的是抛出一个 Error 对象或其子类的实例。以下是两个使用 throw 语句的示例,展示了如何在不同场景下手动抛出异常。

示例 1:验证用户输入

在这个例子中,我们编写了一个函数来验证用户的年龄。如果年龄不在合理的范围内(例如小于0或大于120),我们将抛出一个自定义错误。这种做法可以帮助我们在程序中更早地发现并处理无效数据。

function validateAge(age) {
  if (age < 0 || age > 120) {
    throw new Error("Invalid age. Please enter a value between 0 and 120.");
  }
  return "Age is valid.";
}

try {
  console.log(validateAge(-3)); // 这将触发抛出异常
} catch (error) {
  console.error("Validation failed:", error.message);
}

输出结果将会是:

Validation failed: Invalid age. Please enter a value between 0 and 120.

在这里插入图片描述

示例 2:自定义错误类型

有时候你可能想要创建自己的错误类型,以便更具体地描述问题。通过继承内置的 Error 类,你可以创建一个自定义错误类,并在适当的时候抛出它。

// 定义一个自定义错误类型
class NegativeValueError extends Error {
  constructor(message) {
    super(message); // 调用父类构造函数设置 message 属性
    this.name = "NegativeValueError"; // 设置错误名称
  }
}

function checkPositive(value) {
  if (value < 0) {
    throw new NegativeValueError("Value cannot be negative.");
  }
  return "Value is positive.";
}

try {
  console.log(checkPositive(-10)); // 这将触发抛出自定义异常
} catch (error) {
  if (error instanceof NegativeValueError) {
    console.error(`${error.name}: ${error.message}`);
  } else {
    console.error("An unexpected error occurred:", error);
  }
}

输出结果将会是:

NegativeValueError: Value cannot be negative.

在这里插入图片描述

在这个例子中,我们定义了一个名为 NegativeValueError 的自定义错误类,并在 checkPositive 函数中使用它来检查数值是否为正数。当检测到负数时,抛出了一个 NegativeValueError 实例。然后,在 catch 块中,我们特别捕获了这个自定义错误类型,并提供了相应的错误信息。

这两个示例展示了如何使用 throw 语句来增强代码的健壮性和可读性。通过抛出自定义错误,你可以更精确地控制应用程序的行为,并使错误更容易理解和处理。

3. 自定义错误类型

在JavaScript中,创建自定义错误类型可以通过继承内置的 Error 类来实现。这使得你可以为特定类型的错误提供更详细的描述和处理逻辑。下面是一个创建自定义错误类型的示例,展示了如何定义、抛出并捕获这种错误。

示例:创建并使用自定义错误类型

假设我们正在开发一个应用程序,其中有一个函数用于验证用户输入的年龄。为了更好地处理无效的年龄值,我们可以定义一个名为 InvalidAgeError 的自定义错误类型,并在适当的时候抛出它。

// 定义一个自定义错误类型
class InvalidAgeError extends Error {
  constructor(message) {
    super(message); // 调用父类构造函数设置 message 属性
    this.name = "InvalidAgeError"; // 设置错误名称
  }
}

// 验证年龄的函数
function validateAge(age) {
  if (age < 0 || age > 120) {
    throw new InvalidAgeError("Age must be between 0 and 120.");
  }
  return "Age is valid.";
}

// 测试函数
try {
  console.log(validateAge(-5)); // 这将触发抛出自定义异常
} catch (error) {
  if (error instanceof InvalidAgeError) {
    console.error(`${error.name}: ${error.message}`);
  } else {
    console.error("An unexpected error occurred:", error);
  }
}
输出结果将会是:
InvalidAgeError: Age must be between 0 and 120.

在这里插入图片描述

在这个例子中:

  • 定义自定义错误类型:我们通过扩展 Error 类创建了一个新的错误类型 InvalidAgeError。构造函数接收一个消息参数,并调用父类的构造函数来初始化这个消息。此外,我们还设置了 name 属性以标识错误类型。

  • 抛出自定义错误:在 validateAge 函数中,如果传入的年龄不在合理范围内(即小于0或大于120),我们就抛出了一个新的 InvalidAgeError 实例,并传递了适当的错误信息。

  • 捕获并处理自定义错误:在 try...catch 块中,我们特别检查了捕获到的错误是否是 InvalidAgeError 的实例。如果是,则输出特定的错误信息;否则,处理其他类型的意外错误。

这种方式不仅提高了代码的可读性和维护性,而且有助于更精确地描述和处理程序中的不同错误情况。通过定义具体的错误类型,你可以在较大的代码库中更容易地追踪和修复问题。

4. Promise 和异步函数中的错误处理

在JavaScript中,Promiseasync/await 是处理异步操作的主要方式。它们允许你以更线性的方式编写异步代码,并且提供了简洁的错误处理机制。下面是一个结合 Promiseasync/await 的示例,展示了如何优雅地处理异步函数中的错误。

示例:使用 Promiseasync/await 处理异步请求中的错误

假设我们正在开发一个应用程序,需要从API获取用户数据。我们将展示如何通过 fetch 函数发起网络请求,并使用 Promiseasync/await 来处理可能发生的错误。

// 模拟一个可能会失败的 API 请求
function fetchData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url === 'https://api.example.com/data') {
        resolve({ id: 1, name: "John Doe" });
      } else {
        reject(new Error("Failed to fetch data from the server."));
      }
    }, 1000); // 模拟网络延迟
  });
}

// 异步函数来获取并处理数据
async function getUserData() {
  try {
    const response = await fetchData('https://api.example.com/data');
    console.log("User data fetched successfully:", response);
  } catch (error) {
    console.error("Error fetching user data:", error.message);
  }
}

// 调用异步函数
getUserData();

// 测试错误处理
async function testErrorHandling() {
  try {
    const response = await fetchData('https://api.example.com/invalid-url');
    console.log("This should not print.");
  } catch (error) {
    console.error("Error handling test:", error.message);
  }
}

// 调用测试函数
testErrorHandling();
输出结果将会是:
User data fetched successfully: { id: 1, name: 'John Doe' }
Error handling test: Failed to fetch data from the server.

在这里插入图片描述

在这个例子中:

  • 模拟 API 请求:我们定义了一个 fetchData 函数,它返回一个 Promise。这个 Promise 在经过一段模拟的网络延迟后,根据传入的 URL 决定是解析(resolve)还是拒绝(reject)。

  • 异步函数getUserData 是一个异步函数,它调用了 fetchData 并使用 await 等待结果。如果请求成功,则输出用户数据;如果发生错误,则捕获并输出错误信息。

  • 测试错误处理testErrorHandling 函数用于测试错误处理逻辑。当提供一个无效的URL时,fetchData 将会抛出一个错误,该错误被 catch 块捕获并处理。

这种方式不仅使代码更加易读和易于维护,而且确保了即使异步操作失败,程序也能优雅地处理这些情况。通过 try...catch 结构,你可以集中处理所有可能的异常,从而提高代码的健壮性和用户体验。

此外,Promiseasync/await 的组合使用还简化了回调地狱的问题,使得异步代码的编写和调试变得更加直观。

5. 全局错误处理

在JavaScript中,全局错误处理用于捕获那些未被局部 try...catch 捕获的异常。这对于确保应用程序即使在遇到未预见的问题时也能保持一定的稳定性非常重要。下面是一个示例,展示了如何设置全局错误处理器来捕获未处理的异常和拒绝的Promise。

示例:设置全局错误处理器

假设我们有一个简单的Web应用,它可能会抛出一些未处理的异常或有未处理的Promise拒绝。我们将设置全局错误处理器来捕获这些情况,并记录相关信息到控制台。

1. 捕获未处理的异常

我们可以使用 window.onerror 或者通过监听 'error' 事件来捕获未处理的异常。以下是使用事件监听器的方式:

// 全局错误处理器:捕获未处理的异常
window.addEventListener('error', function(event) {
  console.error(
    "Uncaught exception at line " + event.lineno + 
    " in " + event.filename + ": " + event.message
  );
  // 可以在这里进行更详细的日志记录、上报给服务器等操作
}, true);
2. 捕获未处理的 Promise 拒绝

对于未处理的Promise拒绝,我们可以监听 'unhandledrejection' 事件:

// 全局错误处理器:捕获未处理的 Promise 拒绝
window.addEventListener('unhandledrejection', function(event) {
  console.error("Unhandled promise rejection:", event.reason);
  // 同样可以在此处添加更多的错误处理逻辑
});
3. 测试全局错误处理器

为了测试上面设置的全局错误处理器,我们可以故意触发一些错误:

// 测试未处理的异常
function triggerError() {
  undefinedVariable; // 这将导致 ReferenceError
}

// 测试未处理的 Promise 拒绝
function triggerPromiseRejection() {
  Promise.reject(new Error("This is an unhandled promise rejection"));
}

// 调用测试函数
setTimeout(triggerError, 500); // 延迟执行以确保事件监听器已经设置好
setTimeout(triggerPromiseRejection, 1000); // 再延迟一点时间执行
输出结果将会是:
Uncaught exception at line 0 in : Script error.
Uncaught ReferenceError: undefinedVariable is not defined
    at triggerError (<anonymous>:2:3)
Uncaught (in promise) Error: This is an unhandled promise rejection
    at triggerPromiseRejection (<anonymous>:7:18)

在这里插入图片描述

在这个例子中:

  • 捕获未处理的异常:当 triggerError 函数尝试访问一个未定义的变量时,会抛出一个 ReferenceError。这个错误会被全局错误处理器捕获,并输出详细信息。

  • 捕获未处理的 Promise 拒绝triggerPromiseRejection 函数中,我们故意拒绝了一个Promise,并且没有提供 .catch() 处理程序。因此,这个拒绝会被全局的 'unhandledrejection' 事件监听器捕获,并输出错误原因。

通过这种方式,你可以确保即使某些代码部分未能正确处理它们自己的错误,你的应用程序仍然能够记录这些错误并采取适当的措施(例如发送错误报告给开发者)。这有助于提高应用程序的稳定性和用户体验,同时为调试提供了宝贵的信息。

最佳实践

  • 明确错误信息:总是提供有意义的错误消息,帮助开发者快速定位问题。
  • 避免忽略错误:不要简单地用空的 catch 块忽略所有错误,应该至少记录下来。
  • 合理使用自定义错误类型:根据不同的错误场景创建特定的错误类,有助于更好地理解和处理错误。
  • 局部处理优先:尽量在最接近错误发生的地点处理它们,而不是依赖于全局错误处理器。
  • 测试异常路径:确保你的测试覆盖了正常和异常情况,以验证错误处理逻辑的有效性。

通过正确地使用这些技术,你可以提高JavaScript应用的健壮性和可靠性,同时为用户提供更好的体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2258470.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java面试之多线程状态(三)

此篇接上一篇Java面试之实现多线程(二) Java线程可以拥有自己的操作数栈、程序计数器、局部变量表等资源&#xff0c;它与同一进程内的其他线程共享该进程的所有资源。Java线程在生命周期内存在多种状态&#xff0c;可以通过Thread.State枚举类获取线程状态。如图所示有NEW(新建…

数据仓库:智控数据中枢

数据仓库 一. 什么是数据仓库&#xff1f;二. 传统数据库与数据仓库的区别&#xff1f;三. 数据仓库详解&#xff08;一&#xff09;. 数据分析&#xff08;二&#xff09;. 特点1. 面向主题2. 集成的3. 反应历史变化 四. 如何搭建数据仓库&#xff08;一&#xff09;. 数据平台…

【全连接神经网络】核心步骤及其缺陷

前向传播 计算公式&#xff08;其中一种&#xff09; x1/x2&#xff1a;输入值&#xff0c;一般是神经网络上一层的输出或者输入数据本身&#xff0c;上图中表示两个节点w11 w13&#xff1a;权重&#xff0c;在神经网络中&#xff0c;权重是学习的参数&#xff0c;表示每个输入…

微服务的问题

1.创建maven项目 然后配置对应的maven地址 2.创建父工程 删掉其中的src文件 在父pom中进行版本依赖和管理 如下图所示 3.在子文件中进行添加依赖 然后刷新maven进行下载

CAPL如何设置或修改CANoe TCP/IP协议栈的底层配置

在CANoe中创建网络节点作为以太网主机时,可以给其配置独立的TCP/IP Stack。 配置的协议栈有一些底层配置参数可以在界面上设置或修改,比如: MTU上图中MTU显示500只是图形界面显示错误,正确值是1500。 TCP延迟确认这些参数也可以通过CAPL动态配置,甚至CAPL还可以配置很多界…

计算机视觉与医学的结合:推动医学领域研究的新机遇

目录 引言医学领域面临的发文难题计算机视觉与医学的结合&#xff1a;发展趋势计算机视觉结合医学的研究方向高区位参考文章结语 引言 计算机视觉&#xff08;Computer Vision, CV&#xff09;技术作为人工智能的重要分支&#xff0c;已经在多个领域取得了显著的应用成果&…

微搭低代码AI组件单词消消乐从0到1实践

目录 1 为什么要开发单词消消乐2 需要具备什么功能3 采用什么技术方案实现4 逻辑设计4.1 数据结构设计4.2 游戏的核心逻辑4.3 数据设计 5 代码详解5.1 导入依赖5.2 定义函数组件5.3 数据初始化5.4 状态定义5.5 打乱解释的逻辑5.6 定义选择单词的函数5.7 定义选择解释的函数5.8 …

learn-(Uni-app)输入框u-search父子组件与input输入框(防抖与搜索触发)

1.父子组件u-search &#xff08;1&#xff09;父组件 <!-- 父组件 --> <template> <div><searchBar change"change" search"search"></searchBar> </div> </template> <script> // 子组件搜索 import…

SpringBoot【九】mybatis-plus之自定义sql零基础教学!

一、前言&#x1f525; 环境说明&#xff1a;Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE mybatis-plus的基本使用&#xff0c;前两期基本讲的差不多&#xff0c;够日常使用&#xff0c;但是有的小伙伴可能就会抱怨了&#xff0c;若是遇到业务逻辑比较复杂的sq…

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题 这篇文章是接我cocos专栏的上一篇文章继续写的&#xff0c;我上一篇文章写的是 cocos 开发触摸屏项目&#xff0c;需要嵌入一个网页用来展示&#xff0c;最后通过 electron 打包成 exe 程序&#xff0c;而且网页里面…

webrtc学习----前端推流拉流,局域网socket版,一对一

提示&#xff1a;局域网socket版 文章目录 [TOC](文章目录) 前言一、教程二、webrtc工作流程三、推流端四、拉流五、socket服务六、效果七、备注总结 前言 ‌‌‌‌‌WebRTC&#xff08;Web Real-Time Communication&#xff09;‌是一种实时通讯技术&#xff0c;允许网络应用或…

net/http: TLS handshake timeout 问题

最近系统偶现”net/http: TLS handshake timeout“&#xff0c;而且都集中在同一个机房&#xff0c;这个报错还是第一次见&#xff0c;产生的原因和解决的方案都比较有意思。 现场 报错的信息为&#xff1a; Error sending request:%!(EXTRA *url.ErrorGet "https://**…

HTML简单贪吃蛇游戏

1.功能说明&#xff1a; 游戏网格&#xff1a;一个20x20的网格&#xff0c;每个格子的大小为20x20像素。 蛇的移动&#xff1a;玩家可以通过方向键&#xff08;左、上、右、下&#xff09;控制蛇的移动。 食物生成&#xff1a;食物会在随机位置生成&#xff0c;当蛇吃到食物时…

http 502 和 504 的区别

首先看一下概念&#xff1a; 502&#xff1a;作为网关或者代理工作的服务器尝试执行请求时&#xff0c;从上游服务器接收到无效的响应。503&#xff1a;由于临时的服务器维护或者过载&#xff0c;服务器当前无法处理请求。这个状况是临时的&#xff0c;并且将在一段时间以后恢…

基于SpringBoot医疗挂号系统(计算机毕业设计)+万字说明文档

系统合集跳转 源码获取链接 一、系统环境 运行环境: 最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 IDE环境&#xff1a; Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以 tomcat环境&#xff1a; Tomcat 7.x,8.x,9.x版本均可 操作系统…

【青牛科技】D4800 AB类 立 体 声 耳 机 音 频 功 率 放 大器电路可应用在便携式数字 音 响 设 备 中 作 功 率 放 大 用

概 述 &#xff1a; D4800 是 一 块 AB类 立 体 声 耳 机 音 频 功 率 放 大器电路。 D4800 在5V电 源 时 输 出 功 率 最 高 可 达 290mW(8 Ω 负载&#xff0c; 失真度 10%)。适合在便携式数字 音 响 设 备 中 作 功 率 放 大 用 。 主要特点&#xff1a; 电源电压&#x…

vue3+vite接入iconify,支持离线

前言 找一个图标太难了。Element-plus Icon的不够用。阿里巴巴的iconfont又比较麻烦。如果有自己的UI组件也可以考虑。 为了快速开发&#xff0c;我选择unocss iconify。 网上的教程太多了&#xff0c;建议大家直接看文档&#xff0c;其实配置步骤只有几步&#xff0c;不多。…

SD Express 卡漏洞导致笔记本电脑和游戏机遭受内存攻击

Positive Technologies 最近发布的一份报告揭示了一个名为 DaMAgeCard 的新漏洞&#xff0c;攻击者可以利用该漏洞利用 SD Express 内存卡直接访问系统内存。 该漏洞利用了 SD Express 中引入的直接内存访问 (DMA) 功能来加速数据传输速度&#xff0c;但也为对支持该标准的设备…

网页核心页面设计(第8章)

一、伪元素 伪元素是 CSS 中的一种选择器&#xff0c;用于选择某些特定的元素或元素的一部分&#xff0c;而这些元素本身并不存在于文档的结构中。伪元素使得网页设计师可以更灵活地控制样式&#xff0c;从而可以为元素的内容、框架或文本提供额外的样式&#xff0c;增强网页的…

黑马商城微服务复习(5)

MQ 一、同步调用和异步调用1. 同步调用2. 异步调用 二、RabbitMQ1. 基础使用2. 实际操作 怎么用?3. RabbitMQ虚拟主机 数据隔离4. 在JAVA中实现RabbitMQ5. 交换机种类 一、同步调用和异步调用 1. 同步调用 微服务一旦拆分&#xff0c;必然涉及到服务之间的相互调用&#xff…