深入浅出Promise,循序渐进掌握JavaScript异步编程

news2024/12/23 18:20:07

一. Promise基本用法

Promise 是 JavaScript 中处理异步操作的一种方式。它是一个对象,代表了一个异步操作的最终完成或失败的结果。

Promise 有三种状态: pending (进行中)fulfilled (已成功) 和 rejected (已失败)。一旦 Promise 的状态变为 fulfilled 或 rejected ,就称为 resolved (已解决)。在 resolved 状态下, Promise 的结果值就被确定了。

fileOf7174.png

Promise的基本用法如下:

const promise = new Promise((resolve, reject) => {
  // 异步操作...
  if (/* 异步操作成功 */) {
    resolve(result); // 将结果传递给resolve函数
  } else {
    reject(error); // 将错误信息传递给reject函数
  }
});

promise
  .then(result => {
    // 处理异步操作成功的结果
  })
  .catch(error => {
    // 处理异步操作失败的结果
  });

在上面的示例中,我们创建了一个 Promise 对象,并在构造函数中传入一个执行器函数(executor function)。执行器函数接受两个参数, resolve 和 reject 函数,用于将 Promise 的状态改变为 fulfilled 或 rejected 。

执行器函数中进行异步操作,当异步操作成功时,调用resolve函数传递结果值;当异步操作失败时,调用reject函数传递错误信息。

接着,我们通过调用 Promise 的then方法来设置异步操作成功时的回调函数,并通过catch方法来设置异步操作失败时的回调函数。then方法可以链式调用,每个then方法都返回一个新的 Promise 实例,因此可以实现连续的异步操作。

除了thencatch方法外, Promise 还提供了一些其他的方法,如finally方法、Promise.allPromise.race等,用于处理更复杂的异步操作场景。

需要注意的是, Promise 的状态一旦改变就不会再改变。因此,即使异步操作完成后再次调用 resolve 或 reject 函数,也不会对 Promise 的状态产生影响。

fileOf7174.png

二. Promise的高级用法

除了以上介绍基本的用法外, Promise 还提供了一些高级的用法,下面介绍几个常用的高级用法:

  1. Promise.all: Promise.all方法接收一个由 Promise 实例组成的数组作为参数,并返回一个新的 Promise 实例。该新的Promise实例在数组中的所有 Promise 实例都变为fulfilled状态后,才会变为fulfilled状态,并将每个 Promise 实例的结果值组成一个数组传递给回调函数。
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);

Promise.all([promise1, promise2, promise3])
  .then(results {
    console.log(results); // [1, 2, 3]
  });
  1. Promise.race: Promise.race方法同样接收一个由 Promise 实例组成的数组作为参数,并返回一个新的 Promise 实例。该新的 Promise 实例在数组中的第一个 Promise 实例变为fulfilledrejected状态后,即变为对应的状态,并将第一个 Promise 实例的结果(或错误信息)传递给回调函数。
const promise1 = new Promise((resolve) => {
  setTimeout(() => resolve('Promise 1'), 2000);
});

const promise2 = new Promise((resolve) => {
  setTimeout(() => resolve('Promise 2'), 1000);
});

Promise.race([promise1, promise2])
  .then(result => {
    console.log(result); // Promise 2
  });
  1. Promise.resolve: Promise.resolve方法返回一个新的 Promise 实例,该实例的状态为fulfilled,并将传递的值作为结果。

  2. Promise.rejectPromise.reject方法返回一个新的Promise实例,该实例的状态为rejected,并将传递的值作为错误信息。

const promise1 = Promise.resolve('resolved');
promise1.then(result => {
  console.log(result); // resolved
});

const promise2 = Promise.reject(new Error('rejected'));
promise2.catch(error => {
  console.error(error); // Error: rejected
});
  1. Promise.prototype.finally: Promise.prototype.finally方法用于指定不管 Promise 状态如何,都会执行的回调函数。该方法返回一个新的 Promise 实例,它在回调函数执行完毕后,根据之前 Promise 实例的状态,变为对应的状态。
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('done');
  }, 1000);
});

promise
  .then(result => {
    console.log(result); // done
  })
  .catch(error => {
    console.error(error);
  })
  .finally(() => {
    console.log('finally'); // finally
  });

除了上述介绍的方法外,Promise还提供了很多其他的方法,如Promise.allSettledPromise.any等,用于处理更复杂的异步操作场景。

三. Promise的异步编程场景

以下是一些Promise的异步编程场景的例子:

  1. 发起网络请求:当需要从服务器获取数据时,可以使用 Promise 来发起异步网络请求。通过使用 Promise 封装XMLHttpRequestfetch API,我们可以在请求完成后,通过then方法处理返回的数据或错误信息。
function getData(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    
    xhr.onload = function() {
      if (xhr.status === 200) {
        resolve(xhr.responseText);
      } else {
        reject(new Error(xhr.statusText));
      }
    };
    
    xhr.onerror = function() {
      reject(new Error('Network Error'));
    };
    
    xhr.send();
  });
}

getData('https://api.example.com/data')
  .then(response => {
    console.log('Data:', response);
  })
  .catch(error => {
    console.error('Error:',);
  });
  1. 并行执行多个异步操作:当需要同时执行多个异步操作,并在所有操作都完成后进行处理时,可以使用Promise.all方法。Promise.all接受一个包含多个 Promise 对象的数组作为参数,并返回一个新的 Promise 对象,当所有Promise都解决(fulfilled)时,返回的 Promise 对象也将解决(fulfilled),并提供一个包含所有解决值的数组。
const loadData = () => {
  const request1 = getData('https://api.example.com/data1');
  const request2 = getData('https://api.example.com/data2');
  const request3 = getData('https://api.example.com/data3');
  
  return Promise.all([request1, request2, request3]);
};

loadData()
  .then(dataArr => {
    console.log('Data 1:', dataArr[0]);
    console.log('Data 2:', dataArr[1]);
    console.log('Data 3 dataArr[2]);
   .catch(error => {
    console.error('Error:', error);
  }); 
  1. 异步操作的串执行:当需要按照顺序依次执行一系列异步操作,且每个操作依赖上一个操作的结果时,可以通过then方法的链式调用来实现。每个then方法中返回一个新的 Promise 对象,用于传递上一个操作的结果给下一个操作。
getData('https://api.example.com/data1')
  .then(response1 => {
    console.log('Data 1:', response1);
    return getData('https://api.example.com/data2');
  })
  .then(response2 => {
    console.log('Data 2:', response2);
    return getData('https://api.example.com/data3');
  })
  .then(response3 => {
    console.log('Data 3:', response3);
  })
  .catch(error => {
    console.error('Error:', error);
  });

这些例子展示了 Promise 在异步编程中的一些应用场景,包括网络请求、并行执行和串行执行等。通过合理利用 Promise 的特性,我们可以实现更优雅、可读性更高的代码。

fileOf7174.png

四. Promise的影响

Promise 的出现对JavaScript编程带来了以下几个重要的贡献:

  1. 处理异步操作JavaScript是单线程的,异步操作的处理一直是发者们头疼的问题。而 Promise 通过提供一种构化的方式来处理异步操作,避免了回调地狱(callback hell)的问题。 Promise 的链式调用使得异步操作可以按照顺序执行,提高了代码的可读性和可维性。

  2. 错误处理:传统的回调函数方式对错误处理较为繁琐,容易出现遗漏或混乱。而 Promise 通过catch方法提供了统一的错误处理机制,使得错误处理变得简洁明了。同时, Promise 还可以将同步代码和异步代码的错误处理方式统一起来,提高了的一致性。

  3. 并行操作: Promise 的些高级方法如Promise.allPromise.race,使得并行操作变得更加简单。开发者可以很方便地将多个异步操作并行执行,并等待它们全部完成或任一完成后继续进行后续处理。

  4. 更好的代码组织: Promise 的链式调用可以使代码逻辑更加清晰可读。通过将异步操作按照顺序连接起来,能够更好地组织,易于理解和维护。

总的来说, Promise 的出现使得JavaScript在处理异步操作方面变得更加简洁、可读、可维护,提高了开发效率和代码质量。它改变了JavaScript编程的方式,成为现代异步程的重要工具之一。

五. Promise实现的基本原理

Promise 的源码实现原理可以简要概括如下:

  1. 构造函数: Promise 是一个构造函数,当我们使用new关键字创建一个 Promise 对象时,会调用构造函数。构造函数接受一个executor函数作为参数,executor函数在 Promise 对象的实例化过程中立即执行,它接受两个参数:resolvereject

  2. 状态管理: Promise 对象有三个状态:pendingfulfilledrejected。初始状态为pending,执行executor函数时可以调用resolve函数将状态从pending转为fulfilled,或调用reject函数将状态从pending转为rejected。同时, Promise 对象还有一个内部属性value用于保存resolve函数传递的值,或reason来保存reject函数传递的错误信息。

  3. 回调函数: Promise 对象可以通过thencatchfinally等方法注册回调函数,处理异步操作的结果或错误信息。then方法用于注册成功的回调函数,catch方法用于注册失败的回调函数,finally方法则用于注册无论成功或失败都会被调用的回调函数。

  4. 异步操作: Promise 的实现中,可以通过setTimeoutsetImmediate等宏任务和微任务的方法进行异步操作的处理。在和reject函数被调用时,会根据状态的变化,将对应的回调函数添加到任务队列中,并在适当的时候执行。

  5. 链式调用:通过then方法的链式调用,可以将多个异步操作按顺序组织起来。当一个 Promise 对象的状态变为fulfilled时,会执行当前then方法的回调函数,并将回调函数的返回值作为下一个then方法的参数。

总的来说, Promise 的源码实现原理是通过构造函数实例化 Promise 对象,在对象中管理状态、回调函数和异步操作。通过thencatchfinally等方法来注册和执行回调函数,实现了异步操作的顺序控制和错误处理。具体实现会涉及到一些细节,例如任务队列的管理和错误处理的机制,这些都是 Promise 的实现细节。

六. Promise和SetTimeout的区别

Promise 和setTimeout在处理异步操作时有一些区别:

  1. 功能和用途: Promise 是一种用于处理异步操作的对象,它提供了一种更优雅和可靠的方式来处理异步操作的结果和错误。 Promise 可以用于处理异步操作的流程控制,以及实现依赖关系和顺序执行。而setTimeout是浏览器提供的一个函数,用于在指定的时间间隔后执行一次回调函数或代码。

  2. 结构和调用方式: Promise 是一个对象,它有自己的方法和状态。我们通过new关键字创建 Promise 实例,并通过thencatchfinally等方法来注册回调函数。而setTimeout是一个函数,我们可以直接调用它,传递回调函数和延时时间。

  3. 错误处理: Promise 提供了更完善的错误处理机制。我们可以通过注册catch方法来捕获并处理 Promise 中的错误信息。而setTimeout只能通过try-catch语句块来处理回调函数中可能发生的错误。

  4. 异步操作的控制和组织: Promise 允许我们通过串行地、并行地和异步地组织和控制异步操作的流程。通过使用then方法的链式调用,我们可以按照期望的次序执行异步操作,并处理它们的结果。而setTimeout只能用于延时执行一次回调函数,并没有提供更高级的流程控制和依赖管理。

  5. 可读性和可维护性: Promise 的代码往往更加可读、简洁和易于维护。通过链式调用的方式,我们可以将异步操作按照顺序组织起来,并在每一步都进行必要的处理。而setTimeout的代码往往需要通过回调函数的嵌套来处理多个异步操作,使代码变得复杂和难以理解。

综上所述, Promise 和setTimeout在处理异步操作时的功能、用途、结构和调用方式、错误处理、控制和组织方式等方面有一些区别, Promise 更加灵活强大,能够提供更好的异步编程体验。

​​​​​​在这里插入图片描述

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

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

相关文章

如何在SQL Server中恢复多个数据库?

一次性恢复多个 SQL数据库吗可以吗? "是的,可以一次性恢复多个 SQL 数据库。通常情况下,只要备份文件的名称与相应的数据库匹配,且没有附加的日期或时间信息,就可以通过有效的 T-SQL 脚本来完成恢复。如果你希望…

虚幻引擎VR游戏开发03| 键位映射

Enhanced input mapping 按键映射 在虚幻引擎(Unreal Engine)中,Enhanced Input Mapping 是一个用于管理和处理输入(例如键盘、鼠标、手柄等)的系统。它提供了一种更灵活、更强大的方式来定义和响应用户输入&#xff…

MMO移动同步(1)

多个客户端同时连入游戏 这篇会从以下五个部分讲解: 同步的基本概念 完善角色进入及离开处理 CharacterManager(C/S) EntityManager(C/S) 打包运行Win客户端 同步基本概念 同步:角色信息,位置,状态同步;客户端和…

神仙公司名单(北京篇)

欢迎来到小落科技每日分享频道 大家好,秋招已经火热进行中了,不知道大家准备得怎么样了?特别是咱们25届的小伙伴们,有没有找到心仪的目标? 想必大家最近和我一样,忙着在各种招聘平台上搜罗信息&#xff0c…

如何在 Cursor 中使用驭码CodeRider?

驭码CodeRider 是极狐GitLab 公司自研发布的 AIGC 产品,可以用来进行 AI 编程和 DevOps 流程处理。本文分享如何在 Cursor 中使用驭码CodeRider。 Cursor 是近期比较火爆的一款 AI 代码编辑器,通过将 AI 能力引入软件研发来提升软件研发效率。而驭码Cod…

水凝胶透镜是什么?能用来干啥?

大家好,今天我们来了解一项关于蛋白质驱动的水凝胶透镜的研究——《Toward Tunable Protein‐Driven Hydrogel Lens》发表于《Advanced Science》。我们的眼睛晶状体主要由蛋白质构成,在视觉中起重要作用。但人造光学系统要实现类似功能却不容易。近年来…

【设计文档】数据库设计说明书(Word实际项目案例参考)

一、 总述 (一) 编写目的 二、 外部设计 (一) 环境说明 (二) 指导 三、 物理实现 (一) 物理结构 (二) 安全设计 四、 表设计结构 (一&am…

【软件文档】软件系统试运行方案、试运行报告(Word项目实际原件)

一、 试运行目的 (一) 系统功能、性能与稳定性考核 (二) 系统在各种环境和工况条件下的工作稳定性和可靠性 (三) 检验系统实际应用效果和应用功能的完善 (四) 健全系统运行管理体制&…

【数字人】Facevid2vid:用于视频会议的一次性自由视图说话头合成

论文:https://arxiv.org/pdf/2011.15126 github:GitHub - zhanglonghao1992/One-Shot_Free-View_Neural_Talking_Head_Synthesis: Pytorch implementation of paper "One-Shot Free-View Neural Talking-Head Synthesis for Video Conferencing" 一种新颖…

ip地址的管理方法有哪些?是什么

IP地址的管理方法有哪些?随着互联网的快速发展,‌IP地址作为网络设备的唯一标识,‌其管理显得尤为重要。‌有效的IP地址管理不仅可以确保网络的稳定运行,‌还能提高网络资源的利用率。‌本文将深入探讨IP地址的管理方法&#xff0…

网银U盾:财务眼中钉,会计肉中刺!

随着网银U盾的广泛应用,虽然使得财务安全有了大幅提升,但企业财务管理效率却越来越低了。 近期,我们发现,高达85%的企业在采购我们的USB Server时,都是出于网银U盾反复插拔的繁琐、效率低下、管理困难等原因。 想象一…

sqli-labs靶场通关攻略(五十一到六十关)

sqli-labs-master靶场第五十一关 步骤一,尝试输入?sort1 我们发现这关可以报错注入 步骤二,爆库名 ?sort1 and updatexml(1,concat(0x7e,database(),0x7e),1)-- 步骤三,爆表名 ?sort1 and updatexml(1,concat(0x7e,(select group_conc…

CentOS 7 docker 部署遇到内网通,外网不通 问题

CentOS 7 docker 部署遇到内网通,外网不通 问题 [rootlocalhost ~]# systemctl status network ● network.service - LSB: Bring up/down networkingLoaded: loaded (/etc/rc.d/init.d/network; bad; vendor preset: disabled)Active: failed (Result: exit-code) …

多角度解读WMS:探寻仓库管理系统的核心功能

多角度解读 WMS 仓库管理系统 1. 概述 WMS 在数字化工厂中具有举足轻重的地位,它不仅提高了仓储管理的效率与准确性,还能优化整个供应链的管理,支持灵活生产模式,并提供决策支持的关键数据。通过现代前后端技术的架构设计&#xf…

几十块的麦克风能用吗?一文看懂哪个牌子的麦克风好

无论是拍摄短视频、直播还是采访,说一款好的音频设备是非常重要的,它决定了音频质量的高低,如今市面上的麦克风种类也是各式各样的都有,价格上也是参差不齐,有些小伙伴问“几十块的麦克风能用吗”? 我觉得最…

Docker部署项目时的服务端口设置——给容器添加新端口映射

Docker给容器添加新端口映射 1 Docker安装Ubuntu22.042 创建新容器3 给容器添加端口映射3.1 查看运行的容器3.2 查看容器挂载目录3.3 停止容器3.4 停止docker服务3.5 进入容器挂载目录3.6 修改config.v2.json文件3.7 修改hostconfig.json文件3.8 启动docker3.9 启动容器 4 端口…

C语言中volatile与const关键字的深入解析

在C语言编程中,volatile和const是两个非常重要的关键字,它们各自有着独特的用途。本文将深入探讨这两个关键字的工作原理、底层实现机制以及在实际开发中的应用。 volatile关键字 1. 原理与作用 volatile关键字用于告诉编译器,所修饰的变量…

若楠带你初识OpenCV(2)--图片修改、运算,边界填充以及阈值调整

文章目录 OpenCV图片修改1. 图片缩放2. 图片打码3. 图片组合 图像运算1. 直接相加2. add()方法相加3. 权重相加 边界填充阈值调整总结 OpenCV OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,它主要用于实…

Nginx负载均衡数据流分析

1、各机器ip信息 客户端IP:192.168.3.239 Nginx代理服务器IP:192.168.3.241 服务端IP:192.168.3.238 2、架构图(略) 3、 下图是在服务端上面的抓包分析。 下图是在客户端上面的抓包分析: 下图是在代理服务…

32 配置多路由的静态路由

配置多路由的静态路由 一、多路由器的静态路由配置 ​ 配置网络拓扑配置接口IP地址并通过静态路由的配置实现全网的互通 R0: # 进入特权 Router>enable# 进入全局 Router#configure terminal # 进入接口 Router(config)#interface fastEthernet 0/0# 配置IP R…