JavaScript系列——Promise

news2024/11/17 7:32:59

文章目录

    • 概要
    • Promise三种状态
    • 状态改变
    • Promise链式调用
    • Promise处理并发
      • promise.all()
      • promise.allSettled()
      • Promise.any()
      • promise.race()
    • 小结

概要

Promise中文翻译过来就是承诺、预示、有可能的意思。
在JavaScript里面,Promise 是一个对象,表示异步操作最终成功或失败返回的结果值

promise 是一个代理,创建promise对象时,我们不知道异步处理会返回什么值。promise将异步操作下可能发生不同的操作结果事先制定处理逻辑,将其不同状态的值返回出来。这使得异步方法可以像同步方法一样返回值。

使用Promise的不会立即返回异步方法处理的结果值,而是返回一个Promise对象,等待某个合适时机后,通过promise获取对应的结果值。promise对象,可能有以下三种状态,下面详细说明一下

Promise三种状态

  • 待定(pending):初始状态,既没有被兑现,也没有被拒绝
  • 已兑现(fulfilled):意味着操作成功完成。
  • 已拒绝(rejected):意味着操作失败

一个待定状态的Promise,最终状态可以是已兑现并返回一个值,或者是已拒绝并返回一个错误原因

当其中任意一种情况发生时,通过Promise 的then 方法串联的处理程序将会立即调用。

promise对象的状态是不可逆的,一旦其被兑现或者拒绝,即不再处于待定状态,那么则称之为已敲定(settled)
在这里插入图片描述

我们还会听到使用已解决(resolved)这个术语来描述 Promise——这意味着该 Promise 已经敲定(settled),或为了匹配另一个 Promise 的最终状态而被“锁定(lock-in)”,进一步解决或拒绝它都没有影响。

例如以下代码示例:

new Promise((resolveOuter) => {
  resolveOuter(
    new Promise((resolveInner) => {
      setTimeout(resolveInner, 1000);
    }),
  );
});

此 Promise 在创建时已经被解决(因为 resolveOuter 是同步调用的),但它是用另一个 Promise 解决的,因此在内部 Promise 兑现的 1 秒之后才会被兑现,在此之前,一直处于待定状态。在实践中,“解决”过程通常是在幕后完成的,不可观察,只有其兑现或拒绝是可观察的。

状态改变

Promise 对象,可以使用new 关键字进行实例化,语法如下:

new Promise(executor)

Promise() 只能通过new运算符来构造
如果尝试在没有使用 new 的情况下调用它,会抛出 TypeError 异常·。

executor 表示在构造函数中执行的函数,
它接受两个函数作为参数:resolveFunc 和 rejectFunc
其中,executor 中抛出任何错误都会导致Promise 被拒绝,并且返回值被忽略。

executor 是将回调函数的结果与 Promise 关联在一起的自定义代码。编写 executor 的工作由程序员完成。它的函数签名如下面代码所示:

function executor(resolveFunc, rejectFunc) {
  // 通常,`executor` 函数用于封装某些接受回调函数作为参数的异步操作,比如上面的 `readFile` 函数
}

executor 执行与Promise 的对象构造是同步进行的。但作为executor 函数的参数的函数resolutionFunc 和rejectionFunc,一般 要结合异步函数的操作结果来决定调用谁。

resolutionFunc 或者 rejectionFunc 被调用时,另一个 Promise 对象作为函数参数的话,该 Promise 对象就会变为已解决(resolved)。但仍未“敲定(settled)”的待定状态。解决状态下的Promise不一定会导致Promise变成已兑现或者拒绝状态,最终要看作为参数的Promise 状态。

如果调用resolutionFunc (传入参数不是Promise ),Promise 将会成为被兑现(fulfilled)状态
如果调用rejectFunc (传入参数不是Promise ),Promise 对象将会成为拒绝(rejected)状态

成为被兑现或拒绝状态Promise ,都是敲定状态的Promise

只有第一次调用 resolveFunc 或 rejectFunc 会影响 Promise 的最终状态,随后对任一函数的调用都不能更改兑现值或拒绝原因,也不能将其最终状态从“已兑现”转换为“已拒绝”或相反。

一旦 Promise 敲定,它会(异步地)调用任何通过 then()、catch() 或 finally() 关联的进一步处理程序。最终的兑现值或拒绝原因在调用时作为输入参数传给兑现和拒绝处理程序。

Promise链式调用

Promise 原型有三个方法,用于将进一步的操作与已敲定的 Promise 相关联,都是可以返回Promise 对象,因此,他们可以进行串联,形成链式调用,他们分别是:

  • Promise.prototype.then()
    将一个处理兑换或者处理拒绝的处理器附加到Promise 上,并返回Promise。无论Promise 是否被兑现还是被拒绝,处理器都会在Promise敲定时被调用
  • Promise.prototype.catch()
    将一个拒绝处理回调函数附加到 Promise 上,并返回Promise,如果回调被调用,则解决回调的返回值
  • Promise.prototye.finally()
    将一个处理器附加到 Promise 上,并返回Promise,当原始 Promise 被解决时解决。无论 Promise 是否被兑现还是被拒绝,处理器都会在 Promise 敲定时被调用

其中,then 方法最多可以接受两个参数,第一个参数为Promise兑现时的回调函数,第二个参数是Promise 拒绝时的回调函数,每一个then 返回Promise 对象,这个对象可以被用于链式调用,例如以下代码

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 300);
});

myPromise
  .then(handleFulfilledA, handleRejectedA)
  .then(handleFulfilledB, handleRejectedB)
  .then(handleFulfilledC, handleRejectedC);

myPromise 经过第一个then 方法被捕捉后,依然可以再使用then 来处理第一个then 方法返回promise。

then 方法在 可以省略返回promise 对象的回调函数,程序仍会继续链接到下一个链式调用。在最终的.catch()之前,可以安全地省略每个链式调用中处理已拒绝状态的回调函数,如下面的代码示例:

myPromise
  .then(handleFulfilledA)
  .then(handleFulfilledB)
  .then(handleFulfilledC)
  .catch(handleRejectedAny);

如果在某一个then 调用中,需要急切处理错误,那么这种情况需要在then中声明对应的拒绝回调函数。如果不是那么急切,可以在最后使用catch进行捕捉。

一个的Promise的终止条件(返回值条件)决定调用链中下一个Promise的“已敲定”状态。

链中每个已兑现的 Promise 的返回值会传递给下一个 .then(),而已拒绝的 Promise 会把失败原因传递给链中下一个拒绝处理函数。

例如如下代码:

const myPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("foo");
      // reject("foo");
    }, 300);
  });

  myPromise
  .then((value) => `${value} and bar`)
  .then((value) => `${value} and bar again`)
  .then((value) => `${value} and again`)
  .then((value) => `${value} and again`)
  .then((value) => {
    console.log(value);
  })
  .catch((err) => {
    console.error(err);
  });

myPromise 延迟300毫秒后,调用resolveFunc,myPromise 变成已兑现状态,并传入了foo作为函数函数。
紧接着,第一个then被触发调用,value=foo,在第一个then 中,拼接了myPromise 返回值,并返回foo and bar
同理,最后console.log(value);输出的语句为foo and bar and bar again and again and again,即把myPromise 进过各个then串联处理。
每一个then 执行后,返回的Promise 依然是一开始的已兑现状态的myPromise

如下代码:

  myPromise.then().then().then(res=>{
    console.log(res,myPromise.then())
  }).catch(err=>console.log(err))

输出结果,myPromise.then(),依然是已兑现状态的myPromise。
在这里插入图片描述

Promise处理并发

Promise 类还提供了四个静态方法来处理任务的并发

  • Promise.all()
    在所有传入的Promise,全部被兑现兑现任意一个Promise被拒绝都会拒绝
  • Promise.allSettled()
    在所有的Promise 都被敲定(所有状态成已经成功或拒绝)时兑现
  • Promise.any()
    任意一个Promise 被兑现兑现,仅仅在所有的Promise 都拒绝时才会拒绝
  • Promise.race()
    任意一个Promise被敲定时敲定。也就是任意一个Promise 被兑现时被兑现或者任意一个Promise被拒绝时拒绝

以上的所有方法,都是接受一个Promise的可迭代对象,并返回一个新的Promise。

代码示例如下

promise.all()

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// Expected output: Array [3, 42, "foo"]

promise.allSettled()

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) =>
  setTimeout(reject, 100, 'foo'),
);
const promises = [promise1, promise2];

Promise.allSettled(promises).then((results) =>
  results.forEach((result) => console.log(result.status)),
);

// Expected output:
// "fulfilled"
// "rejected"

Promise.any()

const promise1 = Promise.reject(0);
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));

const promises = [promise1, promise2, promise3];

Promise.any(promises).then((value) => console.log(value));

// Expected output: "quick"

promise.race()

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
  // Both resolve, but promise2 is faster
});
// Expected output: "two"

小结

  • Promise 对象可以将异步操作结果进行返回,值可能是异步成果的结果或错误原因
  • Promise 对象有三种状态,待定、被兑现、拒绝
  • 构造Promise会同步执行executor,他需要两个函数作为参数,rejectFunc 和resolveFunc
  • rejectFunc 和resolveFunc调用传入非Promise 对象时,状态会变成已兑现或拒绝的敲定状态
  • 变成敲定状态的Promise,会调用Promise串联的then方法
  • 串联Promise ,调用then()方法返回的是的已敲定的原Promise对象,then回调函数参数值,是上一个函数的返回值
  • Promise执行后,不可以取消和暂停,如果想要达到按照自己节奏来执行异步操作,可以使用generator,它可以操作一步一步来,后续会出文章详细说明。

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

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

相关文章

九州金榜|为什么本科生“回炉”读职校?

近年来,“本科学历+技能证书”成为不少大学毕业生求职时的配置,本科毕业生“回炉”职业院校学习技能的现象引发社会关注。 为什么会引发这种现象发生呢?现在学校教育学的是理论知识,而“回炉”确实学习的实操&#xff…

Mac robotframework+pycharm运行suite报错情况:ImportError: No module named request

报错实例: 当前Preferences–>Tool–>External Tools Suite配置,显示使用的python为2.7版本,robotframework安装在当前版本的python中: 但是我pycharm现在的环境配置的python为3.11,当前使用的RF与当前使用的py…

钥匙翻转了一个面,该怎么识别匹配?

工业自动化中,我们经常遇到这样的问题,两面一样,上料时,翻转了,没人知道,该怎么匹配到?让机器人能抓取上? 两面相似,翻转了,该怎么识别匹配,来料…

GPT Store开业大吉:一场AI技术与创新的盛宴

就在1.11 日,ChatGPT 正式上线 GPT Store ! OpenAI CEO 山姆奥特曼第一时间确认了这个消息: 自从GPTs的概念提出以来,短短两个月内,全球用户已经创造了超过300万个GPTs。 点击 GPT Store 或者进入ChatGpt页面&am…

Arrow:在项目中进行时间处理的强大工具

目录 一、Arrow简介 二、安装与配置 三、基础功能与使用 1. 日期和时间格式转换 2. 时区处理 3. 时间序列分析 四、进阶应用与案例分析 五、性能与优化 六、最佳实践与经验分享 七、总结与展望 在处理日期和时间时,我们经常需要一个精确、可靠的库来帮助我…

vue前端开发自学练习,Props数据传递-类型校验,默认值的设置!

vue前端开发自学练习,Props数据传递-类型校验,默认值的设置! 实际上,vue开发框架的时候,充分考虑到了前端开发人员可能会遇到的各种各样的情况,比如大家经常遇到的,数据类型的校验,再比如,默认…

多端多用户万能DIY商城系统源码:自营+多商户入驻商城系统 独立部署 带完整的安装代码包以及搭建教程

电子商务行业日新月异,许多企业希望能够通过线上商城拓展业务。但是,传统商城系统往往无法满足多样化、个性化的需求,而且开发周期长、成本高。罗峰就来给大家分享一款多端多用户万能DIY商城系统源码,搭建简单。 以下是部分代码示…

TypeScript进阶(四)声明文件

✨ 专栏介绍 TypeScript是一种由微软开发的开源编程语言,它是JavaScript的超集,意味着任何有效的JavaScript代码都是有效的TypeScript代码。TypeScript通过添加静态类型和其他特性来增强JavaScript,使其更适合大型项目和团队开发。 在TypeS…

2024最新适用于 Windows 、Mac 的最佳屏幕录制软件

屏幕录制软件可以帮助我们录制 PC 和MacBook的实时屏幕视频。如果您想为 优酷录制视频,或者您正在为您的公司制作基于视频的项目,并且需要捕获屏幕的实时视频录制,那么我们在此列出了 一 款适合您的 Windows 、Mac的 2024 年最佳屏幕录制软件…

Redis相关报错信息:Could not connect to Redis at 127.0.0.1:6379: 由于目标计算机积极拒绝,无法连接。

报错信息: Could not connect to Redis at 127.0.0.1:6379: 由于目标计算机积极拒绝,无法连接。 报错原因: 访问不到Redis服务 解决方案: 将Redis服务打开! 使用cmd命令行打开本机服务管理: services…

Python算法例35 丑数Ⅰ

1. 问题描述 丑数的定义是,只包含质因子2、3、5的正整数,例如6、8就是丑数,但14不是丑数,因为它包含了质因子7,本例将检测一个整数是不是丑数。 2. 问题示例 给出num8,返回True;给出num14&am…

thinkphp美容SPA管理系统源码带文字安装教程

thinkphp美容SPA管理系统源码带文字安装教程 运行环境 服务器宝塔面板 PHP 7.0 Mysql 5.5及以上版本 Linux Centos7以上 基于thinkphp3.23B-JUI1.2开发,权限运用了Auth类认证,权限可以细分到每个功能, 增删改查功能一应俱全,整合了…

PostgreSQL 配置文件、数据储存目录

文章目录 查询配置文件所在位置查询数据储存目录PostgreSQL的数据目录 查询配置文件所在位置 show config_file; -- 查询配置文件所在位置查询数据储存目录 show data_directory; -- 查询数据储存目录PostgreSQL的数据目录 在PostgreSQL的数据目录(C:\Program…

el-tree多个树进行节点同步联动(完整版)

2024.1.11今天我学习了如何对多个el-tree树进行相同节点的联动效果,如图: 这边有两棵树,我们发现第一个树和第二个树之间会有重复的指标,当我们选中第一个树的指标,我们希望第二个树如果也有重复的指标也能进行勾选上&…

什么是冒泡排序?如何实现?

一、是什么 冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法 冒泡排序的思想就是在每次遍历一遍未排序的数列之后,将一个数据元素浮上去(也就是排好了一个数据) 如同碳酸饮料中二氧化碳的…

微信小程序的支付流程

面试官:说说微信小程序的支付流程? 一、前言 微信小程序为电商类小程序,提供了非常完善、优秀、安全的支付功能 在小程序内可调用微信的API完成支付功能,方便、快捷 场景如下图所示: 用户通过分享或扫描二维码进入商…

A股风格因子看板 (2024.01第6期)

该因子看板跟踪A股风格因子,该因子主要解释沪深两市的市场收益、刻画市场风格趋势的系列风格因子,用以分析市场风格切换、组合风格景 露等。 今日为该因子跟踪第6期,指数组合数据截止日2023-12-31,要点如下 近1年A股风格因子收益走…

NODE笔记 1 http模块

简单的http模块使用 文章目录 前言 node 提供了 http 模块,首先需要简单的介绍http http协议(超文本传输协议),在web和网络领域都十分重要。在客户-服务通讯的请求响应中,报文大都是基于http。 可以先新建一个简单的…

springCould中的Stream-从小白开始【12】

🥚今日鸡汤🥚 见过一些人,他们朝九晚五😭,有时也要加班,却能把生活过得很😎有趣。他们有自己的爱好,不怕独处。他们有自己的坚持,哪怕没人在乎。🤦‍♂️ 开心…