Promise 调用 async 函数内代码时候的错误和解决方案

面试官:小伙子,你的数组去重方式惊艳到我了

异步编程是现代 Web 开发中的一个重要主题。JavaScript 提供了多种异步编程模式,在其中,Promise 是一种广泛使用的模式之一。它使得我们可以避免回调地狱,提高代码的可读性和可维护性。而 async/await 则更进一步地简化了异步代码的书写。本文讨论在使用 Promise 调用 async 函数内部代码时可能出现的错误,并提供解决方案。

问题描述

看下面一个简单的例子,使用 Promise 调用一个 async 函数,并在其内部调用另一个 async 函数:

----- -------- ------------ -
  ------ --- --------------- -- ------------- -- ----------------- ------
-

----- -------- ------------ -
  ----- ------ - ----- ------------
  ------------------- -----------
  ------ -------
-

------------------------ -- -------------------- ------------

这段代码输出的结果应该是:

------ -----
------- -----

事实上,大多数情况下,代码运行结果确实如此。但是,当 innerAsync 函数内部抛出异常时,会发生什么呢?我们来修改一下代码,让 innerAsync 抛出一个异常:

----- -------- ------------ -
  ------ --- ----------------- ------- -- ------------- -- ---------------- ------
-

----- -------- ------------ -
  --- -
    ----- ------ - ----- ------------
    ------------------- -----------
    ------ -------
  - ----- ------- -
    --------------------- ----------
    ------ -------
  -
-

------------------------ -- -------------------- ------------

这段代码会输出:

------ -----
------- -----

我们可以看到, innerAsync 函数内部抛出的异常被 outerAsync 函数中的 catch 块捕获了,并返回了一个 error 字符串。但是,由于 Promise 的特性,错误的传播没有停止。实际上,我们可以发现控制台上有一条未捕获的错误栈信息:

这条信息表明我们没有对 innerAsync 函数抛出的错误做出响应,这可能会引起潜在的问题。

解决方案

出现上述问题的原因是在内部 async 函数中 throw 的错误从 Promise 里泄漏出来。在其外部的 try-catch 块中抓住这些错误并不够。我们还需要确保只要异步操作出了问题,我们的 Promise 链就中断。

一种解决方案是将 innerAsync 函数中的 Promise 对象从外部创建,提供一个 catch 块:

-------- ------------ -
  ------ --- ----------------- ------- -- -
    ------------- -- ---------------- -----
  -------------- -- -
    --------------------- ----------
    ----- -----
  --
-

----- -------- ------------ -
  --- -
    ----- ------ - ----- ------------
    ------------------- -----------
    ------ -------
  - ----- ------- -
    --------------------- ----------
    ------ -------
  -
-

------------------------ -- -------------------- ------------

这段代码的输出结果是:

------ -----
------ ---------
------- -----

现在,innerAsync 函数内部的错误被正常捕获和处理,Promise 链被正确地中断,并且我们在未捕获错误处得到了更有用的错误栈信息。即使 innerAsync 函数不使用 async/await,这种做法也是适用的。

除了 catch 内部抛出错误外,在 async 函数内使用 throw 抛出异常,然后在异步操作的 Promise 链中的 catch 中重新抛出该异常也会引起类似的问题。同样地,以下代码也需要进行相应的修改:

----- -------- ------------ -
  ------ --- ----------------- ------- -- -
    ------------- -- ---------------- -----
  --
-

----- -------- ------------ -
  --- -
    ----- ------ - ----- ------------
    ------------------- -----------
    ----- --- --------------
  - ----- ------- -
    --------------------- ----------
    ----- -----
  -
-

------------------------ -- ------------------- -----------

在 innerAsync 函数中引入 catch 块或者在 Promise 上使用 done() 方法可以实现相同的效果。但是这些方法有它们各自的弊端。

  • catch 块中,任何抛出的错误都会被视为 Promise 链中的正常返回值,并将 Promise 链继续传递下去。这可能会不期望地影响 Promise 链中异常的处理。例如,考虑 Promise.all() 中的情况。实际上,一个 Promise 被视为 rejected 后,Promise.all() 立即返回。因此,最好在 Promise.all() 之前检查所有 Promise 的 resolved/rejected 状态,并在出现错误时中断 Promise 链。
  • done() 方法与 Promise 具有相同的 API,不同之处在于该方法不返回 Promise 对象,而是在抛出异常时直接抛出该异常。因此,虽然该方法可以避免适用 catch 块时的误解,但在使用时必须格外小心。

无论使用哪种方法,都要确保在异步操作时出现的任何错误都能够被正确处理和传递。

结论

在使用 Promise 调用 async 函数内部代码时,错误可能会沿着 Promise 链泄漏出来,导致高级错误处理方式失效。为了避免这种情况,我们应该在异步操作的 Promise 链中正确地中断错误传播,并确保所有错误都得到正确处理。以上所述的解决方案是可行的选项之一。我们需要谨慎地思考每个异步操作所必须的异常处理机制,并根据情况进行自定义处理。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/670b9dfd66ef9cf37faa86f3


猜你喜欢

  • 如何使用 Sequelize ORM 实现数据加密

    在开发 web 应用程序时,数据加密是非常重要的。加密可以保障数据在传输和储存的过程中不被非法访问和篡改。在前端开发中,通过使用 Sequelize ORM 可以很方便地实现数据模型的创建、更新和删除...

    5 天前
  • Express.js 中使用 PM2 进行应用的自动化部署和管理

    简介 在现代化的 Web 开发中,前端技术无疑是至关重要的一环。而 Express.js 作为一个流行的 Node.js 框架,被广泛应用于开发 Web 应用程序。

    5 天前
  • Node.js 错误处理实践:通过 Promise.all 统一捕获错误

    前言 在 Node.js 中,异常处理是开发过程中必不可少的部分。正确而准确地处理异常,可显著提高应用程序的可靠性和性能。在本文中,我们将深入了解 Node.js 中如何使用 Promise.all(...

    5 天前
  • 使用 ESLint 检查你的 Vue.js 代码

    随着 Vue.js 的流行,越来越多的开发者开始使用这个优秀的前端框架来构建强大的 Web 应用程序。然而,如果你想要写出高质量的 Vue.js 代码,就需要一个可以帮助你检查代码错误的工具。

    5 天前
  • 如何使用 Tailwind CSS 优化文本样式 | 开发者头条

    如何使用 Tailwind CSS 优化文本样式 Tailwind CSS 是一款适用于现代Web的实用型 CSS 框架,它使用一组小的、互相独立的类来快速构建复杂的UI。

    5 天前
  • 使用 Mocha 进行 React Native 组件测试的方法和技巧

    React Native 是一个受欢迎的跨平台移动应用程序开发框架,它使用 JavaScript 和 React 来构建优秀的应用程序。随着 React Native 的发展,越来越多的人开始使用它来...

    5 天前
  • 使用 Koa.js 的健康检查和运营商

    随着我们的 web 应用程序变得越来越复杂,我们需要用尽可能少的时间和精力来快速检查系统状态,并及时了解发生了什么。Koa.js 是一种基于 Node.js 的框架,它提供了一些有用的工具来帮助我们处...

    5 天前
  • 面向 React Native 开发的 GraphQL 优化方案

    前言 GraphQL已经成为现代 Web 开发中不可或缺的一部分,而React Native在移动端应用中也扮演着越来越重要的角色。两者结合,既可以轻松地管理应用中的数据,又能快速地开发出高效的移动应...

    5 天前
  • CSS Reset 入门指南

    随着前端开发的日益发展,网页设计越来越注重细节和精度。然而,在不同浏览器、操作系统和设备中,CSS 样式表可能会有不同的默认值,这就导致一个在某些浏览器上看起来很棒的网页在其他浏览器上可能很难看。

    5 天前
  • 使用 Service Worker 预加载 PWA 应用的核心资源

    在现代 Web 应用中,PWA(Progressive Web Apps)应用的活跃度不断增加。PWA 应用在终端设备上无需下载安装即可使用,这给终端用户带来极大的便利。

    5 天前
  • SASS 中 Placeholder 选择器的使用与优化建议

    在前端开发中,CSS 是不可或缺的一部分,而 SASS 则是目前最为普及的 CSS 预处理器之一。在 SASS 中,有一种非常强大的选择器——Placeholder 选择器,它可以帮助我们更加高效地编...

    5 天前
  • React 教程:从入门到实践

    React 是一款流行的前端 JavaScript 框架,由 Facebook 开发。React 提供了一种可复用、可组合的 UI 组件的视图层,让开发者能够更轻松地构建高效、可维护的 Web 应用。

    5 天前
  • 如何用 Babel 编译 ES6 模块后,在 Node.js 中正确引用?

    在现代前端开发中,ES6 已经成为了主流的 JavaScript 语言标准,然而,ES6 标准中的模块化系统并未得到广泛支持,这就不得不依赖转换工具将 ES6 模块转换为 CommonJS 模块。

    5 天前
  • 使用 Custom Elements 实现选择器组件(Picker)

    在前端开发中,常常需要使用选择器组件(Picker),用于选择一个或多个选项。这些组件可以是下拉菜单、弹出框、滑动选择等形式,而使用 Custom Elements 可以帮助我们更加轻松地创建这些组件...

    5 天前
  • 使用 Hapi.js 创建基本的登录和注册表单

    在今天的互联网时代,大多数网站都需要用户进行登录和注册。在前端领域,提供一个好的登录和注册表格往往是网站的基础之一。使用 Hapi.js 即可方便地快速创建基本的登录和注册表单,并且其代码易于维护。

    5 天前
  • Docker 部署 Fastify 应用程序的技巧

    Docker 是一个流行的容器化技术,它可以帮助开发人员快速部署应用程序,提高开发效率。Fastify 是一个快速、低开销的 Node.js Web 框架,使用它可以创建高性能的 Web 应用程序和 ...

    5 天前
  • Angular 中如何使用 jQWidgets 控件库增强用户交互体验

    在现代的 Web 应用程序中,用户交互体验是非常重要的。要让一个应用程序拥有良好的用户交互体验,需要使用一些强大的控件库,例如 jQWidgets。jQWidgets 是一个高质量的 jQuery 控...

    5 天前
  • 优化 React 单元测试:使用 Enzyme 进行组件测试

    单元测试是前端开发中非常重要的一环。在 React 开发中,单元测试也变得越来越重要。在进行单元测试时,我们需要对组件进行测试,以确保我们的组件可以正常工作并且在更改代码时不会引入新的错误。

    5 天前
  • Web Components 中的路由方案选择及其实现技巧

    前言 Web Components 的出现让前端开发更加灵活,但同时也带来了一些挑战。其中之一是如何有效地管理 Web Components 之间的路由。在本文中,我们将讨论 Web Componen...

    5 天前
  • 在使用 Mocha 测试中遇到的 “cannot find module'should'” 的解决方法

    在使用 Mocha 进行前端测试时,我们可能会遇到一个错误提示:“cannot find module 'should'”。因为 should 是一个非常常用的断言库,所以这个问题困扰了很多前端工程师...

    5 天前

相关推荐

    暂无文章