0

0

Async/Await 与 Promises:JavaScript 初学者简单指南

DDD

DDD

发布时间:2024-12-13 17:09:01

|

664人浏览过

|

来源于dev.to

转载

async/await 与 promises:javascript 初学者简单指南

您是否有过这样的感觉:您在咖啡店排队等候 javascript 来取拿铁咖啡?异步编程常常给人这样的感觉——同时处理多个订单可能会让您陷入等待。幸运的是,promisesasync/await 等工具可确保流程保持平稳高效,让您的代码继续运行而不会出现延迟。

在本指南中,我们将详细介绍 promise 的工作原理、引入 async/await 的原因,以及它如何简化异步代码的编写。无论您是试图掌握这些概念的初学者,还是想清楚何时使用每种方法,本文都将帮助您掌握基础知识。

什么是承诺?

promise 是 javascript 中处理异步操作的基本概念。从本质上讲,promise 代表了现在稍后永远可用的值。将其视为包裹的追踪号码:虽然您还没有收到包裹,但追踪号码让您确信包裹正在运送途中(或者让您知道是否出现问题)。

基于“现在、以后或永远”的叙述,promise 实际上在以下三种状态之一中运行:

立即学习Java免费学习笔记(深入)”;

  • pending:异步操作尚未完成。
  • 已完成:操作已成功完成,promise 现在保存结果。
  • 已拒绝:出了点问题,promise 提供了一个错误。

创建和使用 promise 涉及一个简单的 api。以下是定义 promise 的方法:

const fetchdata = new promise((resolve, reject) => {
  settimeout(() => {
    const data = { id: 1, name: "javascript basics" };
    resolve(data); // simulates a successful operation
    // reject("error: unable to fetch data"); // simulates a failure
  }, 1000);
});

要处理结果,您可以将 .then()、.catch() 和 .finally() 方法链接到 promise 对象:

fetchdata
  .then((data) => {
    console.log("data received:", data);
  })
  .catch((error) => {
    console.error(error);
  })
  .finally(() => {
    console.log("operation complete.");
  });

当 promise 解析成功时执行 then() 方法中的回调。 .catch() 方法中的回调在 promise 解析失败时执行,finally() 方法中的回调在 promise 解析后执行,无论解析结果如何。

promise 的好处

promise 为深层嵌套的回调(通常称为“回调地狱”)提供了一种更干净的替代方案。 promise 允许链接,而不是堆叠回调,从而使操作流程更易于遵循:

dotask1()
  .then((result1) => dotask2(result1))
  .then((result2) => dotask3(result2))
  .catch((error) => console.error("an error occurred:", error));

如果使用传统回调编写相同的代码,它会是什么样子:

dotask1((error1, result1) => {
  if (error1) {
    console.error("an error occurred:", error1);
    return;
  }
  dotask2(result1, (error2, result2) => {
    if (error2) {
      console.error("an error occurred:", error2);
      return;
    }
    dotask3(result2, (error3, result3) => {
      if (error3) {
        console.error("an error occurred:", error3);
        return;
      }
      console.log("final result:", result3);
    });
  });
});

令人困惑,不是吗?这就是为什么 promise 在引入时就改变了 javascript 编码标准。

promise 的缺点

虽然 promises 极大地改进了传统的回调函数,但它们也面临着自己独特的挑战。尽管有这些好处,但它们在复杂的场景中可能会变得笨拙,导致代码冗长和调试困难。

即使使用 .then() 链接,promise 在处理多个异步操作时也会导致代码混乱。例如,使用 .then() 块管理顺序操作和使用 .catch() 进行错误处理可能会让人感觉重复且难以理解。

dotask1()
  .then((result1) => dotask2(result1))
  .catch(task1error, (error) => console.error("an error occurred in task 1:", error));

  .then((result2) => dotask3(result2))
  .catch(task2error, (error) => console.error("an error occurred in task 2:", error));

  .catch((error) => console.error("an error occurred in the chain:", error));

虽然比嵌套回调更清晰,但链接语法仍然很冗长,特别是在需要详细的自定义错误处理逻辑时。此外,忘记在链的末尾添加 .catch() 可能会导致静默失败,从而使调试变得棘手。

此外,promises 中的堆栈跟踪不如同步代码中的堆栈跟踪那么直观。发生错误时,堆栈跟踪可能无法清楚地指示异步流程中问题的根源。

最后,虽然 promise 有助于减少回调地狱,但当任务相互依赖时,它们仍然会导致复杂性。嵌套的 .then() 块可以在某些用例中重新出现,带回一些它们本来要解决的可读性挑战。

输入异步/等待

随着 es2017 (es8) 中 async/await 的引入,javascript 中的异步编程取得了巨大的飞跃。 async/await 构建在 promises 之上,允许开发人员编写外观和行为更像同步代码的异步代码。这使其成为真正的游戏规则改变者,可以提高可读性、简化错误处理并减少冗长。

百宝箱
百宝箱

百宝箱是支付宝推出的一站式AI原生应用开发平台,无需任何代码基础,只需三步即可完成AI应用的创建与发布。

下载

什么是异步/等待?

async/await 是一种旨在使异步代码更易于理解和维护的语法。

async 关键字用于声明一个始终返回 promise 的函数。在此函数中,await 关键字暂停执行,直到 promise 得到解决或拒绝。这会产生线性且直观的流程,即使对于复杂的异步操作也是如此。

下面是 async/await 如何简化您在上面看到的相同代码示例的示例:

async function executetasks() {
  try {
    const result1 = await dotask1();
    const result2 = await dotask2(result1);
    const result3 = await dotask3(result2);
    console.log("all tasks completed successfully:", result3);
  } catch (error) {
    if (error instanceof task1error) {
      console.error("an error occurred in task 1:", error);
    } else if (error instanceof task2error) {
      console.error("an error occurred in task 2:", error);
    } else {
      console.error("an error occurred in the chain:", error);
    }
  }
}

executetasks();

async/await 消除了对 .then() 链的需要,允许代码按顺序流动。这使得遵循逻辑变得更容易,特别是对于需要依次执行的任务。

对于 promise,必须使用 .catch() 在链的每个级别捕获错误。另一方面,async/await 使用 try/catch 整合错误处理,减少重复并提高清晰度。

async/await 产生比 promise 更直观的堆栈跟踪。当发生错误时,跟踪会反映实际的函数调用层次结构,从而减少调试的麻烦。总的来说,async/await 感觉更“自然”,因为它与同步代码的编写方式一致。

比较 promise 和 async/await

正如您已经看到的,async/await 在可读性方面表现出色,尤其是对于顺序操作。 promise 及其 .then() 和 .catch() 链接很快就会变得冗长或复杂。相反,异步/等待代码更容易理解,因为它模仿同步结构。

灵活性

promise 仍然有一席之地,特别是对于并发任务。 promise.all() 和 promise.race() 等方法对于并行运行多个异步操作更有效。 async/await 也可以处理这种情况,但需要额外的逻辑才能达到相同的结果。

// A Promise.all() example
Promise.all([task1(), task2(), task3()])
  .then((results) => console.log("All tasks completed:", results))
  .catch((error) => console.error("An error occurred:", error));

错误处理

虽然使用单个 .catch() 进行集中式错误处理对于线性 promises 链效果很好,但建议对跨链的不同错误类型使用分布式 .catch 调用,以获得最佳可读性。

另一方面,try/catch 块为处理错误提供了更自然的结构,特别是在处理顺序任务时。

表现

就性能而言,async/await 本质上等同于 promises,因为它是建立在 promises 之上的。然而,对于需要并发的任务,promise.all() 可以更高效,因为它允许多个 promise 并行执行,如果任何 promise 拒绝,则快速失败。

何时使用哪个

如果您的任务涉及大量并发操作,例如同时从多个 api 获取数据,promise 很可能是更好的选择。如果您的异步代码不涉及大量链接,那么 promise 也非常适合这种情况,因为它很简单。

另一方面,async/await 在需要顺序执行大量任务或优先考虑可读性和可维护性的情况下表现出色。例如,如果您有一系列相关操作,例如获取数据、转换数据和保存数据,则 async/await 提供干净且同步的结构。这使得跟踪操作流程变得更加容易,并通过 try/catch 块简化了集中式错误处理。 async/await 对于初学者或优先考虑可读代码的团队特别有用。

结论

javascript 提供了两个强大的工具来管理异步操作:promises 和 async/await。 promise 彻底改变了开发人员处理异步任务的方式,解决了回调地狱和启用链接等问题。 async/await 建立在 promises 的基础上,提供了更清晰的语法,让人感觉更加自然和直观,特别是对于顺序任务。

既然您已经探索了这两种方法,您就可以选择最适合您需求的一种了。尝试将基于 promise 的函数转换为 async/await 并观察可读性的差异!

有关更多信息,请查看 mdn promise 文档或尝试交互式编码沙箱!

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
什么是分布式
什么是分布式

分布式是一种计算和数据处理的方式,将计算任务或数据分散到多个计算机或节点中进行处理。本专题为大家提供分布式相关的文章、下载、课程内容,供大家免费下载体验。

407

2023.08.11

分布式和微服务的区别
分布式和微服务的区别

分布式和微服务的区别在定义和概念、设计思想、粒度和复杂性、服务边界和自治性、技术栈和部署方式等。本专题为大家提供分布式和微服务相关的文章、下载、课程内容,供大家免费下载体验。

251

2023.10.07

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

443

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

605

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

443

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

605

2023.08.10

promise的用法
promise的用法

“promise” 是一种用于处理异步操作的编程概念,它可以用来表示一个异步操作的最终结果。Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。Promise的用法主要包括构造函数、实例方法(then、catch、finally)和状态转换。

336

2023.10.12

html文本框类型介绍
html文本框类型介绍

html文本框类型有单行文本框、密码文本框、数字文本框、日期文本框、时间文本框、文件上传文本框、多行文本框等等。详细介绍:1、单行文本框是最常见的文本框类型,用于接受单行文本输入,用户可以在文本框中输入任意文本,例如用户名、密码、电子邮件地址等;2、密码文本框用于接受密码输入,用户在输入密码时,文本框中的内容会被隐藏,以保护用户的隐私;3、数字文本框等等。

427

2023.10.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号