JavaScript系列——Promise

文章目录

    • 概要
    • 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.mzph.cn/news/614484.shtml

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

相关文章

软件测试|解析selenium.common.exceptions.ElementClickInterceptedException错误及解决方法

导言 在自动化测试中,Selenium是一个广泛使用的工具,用于模拟用户在网页上的操作。然而,有时候在执行点击操作时,可能会遇到ElementClickInterceptedException异常,这可能是由于多种原因导致的。本文将深入探讨这个错…

【算法练习】leetcode算法题合集之数组和哈希表篇

重建数组&#xff08;高频&#xff09; LeetCode283.移动零 LeetCode283.移动零 双指针&#xff0c;记录已经处理好的序列的尾部 class Solution {public void moveZeroes(int[] nums) {int k 0;for (int i 0; i < nums.length; i) {if (nums[i] ! 0) {swap(nums, i, k)…

Kafka的简介及架构

目录 消息队列 产生背景 消息队列介绍 常见的消息队列产品 应用场景 消息队列的消息模型 Kafka的基本介绍 简介 Kafka的架构 Kafka的使用 Kafka的shell命令 Kafka的Python API的操作 完成生产者代码 完成消费者代码 消息队列 产生背景 消息队列:指数据在一个容器…

Linux学习记录——삼십팔 网络层IP协议

文章目录 1、了解IP协议2、IP协议报文1、8位服务类型2、16位总长度&#xff08;字节数&#xff09;3、8位生存时间&#xff08;TTL&#xff09; 3、网段划分1、网段划分和CIDR方案2、子网划分简单方法3、IP地址问题的解决方案 4、公网内网1、内网分配2、运营商管理方法 5、路由…

【Python基础】一文搞懂:Python 中 Excel 文件的写入与读取

文章目录 1 引言2 使用 openpyxl2.1 安装 openpyxl2.2 写入 Excel 文件2.3 读取 Excel 文件 3 使用 pandas3.1 安装 pandas 和 openpyxl3.2 写入 Excel 文件3.3 读取 Excel 文件 4 实例演示4.1 安装所需库4.2 封装为excel_example.py脚本文件 5 注意事项6 总结 1 引言 在现代办…

spring-boot项目启动类错误: 找不到或无法加载主类 com.**Application

问题&#xff1a;Springboot项目启动报错&#xff1a;错误: 找不到或无法加载主类 com.**Application 解决步骤&#xff1a; 1.File–>Project Structure 2.Modules–>选中你的项目–点击“-”移除 3.重新导入&#xff1a;点击“”号&#xff0c;选择Import Module&…

【漏洞复现】优卡特脸爱云一脸通智慧管理平台文件上传漏洞

Nx01 产品简介 脸爱云一脸通智慧管理平台是一套功能强大&#xff0c;运行稳定&#xff0c;操作简单方便&#xff0c;用户界面美观&#xff0c;轻松统计数据的一脸通系统。无需安装&#xff0c;只需在后台配置即可在浏览器登录。 功能包括&#xff1a;系统管理中心、人员信息管…

GPT 商店强势来袭,人人都要有自己的 GPTs

作者&#xff1a;苍何&#xff0c;前大厂高级 Java 工程师&#xff0c;阿里云专家博主&#xff0c;CSDN 2023 年 实力新星&#xff0c;土木转码&#xff0c;现任部门技术 leader&#xff0c;专注于互联网技术分享&#xff0c;职场经验分享。 &#x1f525;热门文章推荐&#xf…

网络基础学习(3):交换机

1.交换机结构 &#xff08;1&#xff09;网线接口和后面的电路部分加在一起称为一个端口&#xff0c;也就是说交换机的一个端口就相当于计算机上的一块网卡。 如果在计算机上安装多个网卡&#xff0c;并让网卡接收所有网络包&#xff0c;再安装具备交换机功能的软件&#xff0…

数据加工:从原始数据到有价值的信息

在当今数字化的时代&#xff0c;数据已经成为了企业和组织最宝贵的资产之一。然而&#xff0c;原始数据往往需要经过加工和处理&#xff0c;才能转化为有价值的信息和知识。数据加工是指将原始数据进行处理和分析&#xff0c;以提取有用的信息和知识的过程。数据加工的重要性不…

idea 设置文件头

idea 设置创建文件时自动添加文档注释信息 /** * Description * Author jimaomao * DATE ${DATE} ${TIME} */

【Kafka-3.x-教程】-【五】Kafka-监控-Eagle

【Kafka-3.x-教程】专栏&#xff1a; 【Kafka-3.x-教程】-【一】Kafka 概述、Kafka 快速入门 【Kafka-3.x-教程】-【二】Kafka-生产者-Producer 【Kafka-3.x-教程】-【三】Kafka-Broker、Kafka-Kraft 【Kafka-3.x-教程】-【四】Kafka-消费者-Consumer 【Kafka-3.x-教程】-【五…

React之自定义路由组件

开篇 react router功能很强大&#xff0c;可以根据路径配置对应容器组件。做到组件的局部刷新&#xff0c;接下来我会基于react实现一个简单的路由组件。 代码 自定义路由组件 import {useEffect, useState} from "react"; import React from react // 路由配置 e…

2000-2021年全国各省环境相关指标数据(890+指标)

2000-2021年全国各省环境相关指标数据&#xff08;890指标&#xff09; 1、指标时间&#xff1a;2000-2021年 2、范围&#xff1a;31省市 3、来源&#xff1a;2001-2022年环境统计年鉴 4、指标&#xff1a;工业废水排放总量、工业废水排放达标量、工业废水处理量、化学需氧…

【野火i.MX6ULL开发板】开发板连接网络(WiFi)与 SSH 登录、上电自动登录、设置静态IP、板子默认参数

0、前言 参考之前自己写的&#xff1a; http://t.csdnimg.cn/g60P8 参考资料&#xff1a; [野火]《Linux基础与应用开发实战指南——基于i.MX6ULL开发板》_20230323 从野火官网下载 参考博客&#xff1a; http://t.csdnimg.cn/8uh4O 参考官方文档&#xff1a; https://doc.…

C++力扣题目257--二叉树的所有路径

给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,null,5] 输出&#xff1a;["1->2->5","1->3"]示例 …

Redis:原理速成+项目实战——Redis实战10(Redis消息队列实现异步秒杀)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理速成项目实战——Redis实战9&#xff08;秒杀优化&#xff09; &#x1f4da;订阅专栏&#xff1a;Redis&…

Eureka切换Nacos时发现两个注册中心的解决方法

报错信息如下&#xff0c;意思是发现了两个注册中心 Field autoServiceRegistration in org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration required a single bean, but 2 were found: - nacosAutoServiceRegistration: defined…

数学经典教材有什么?

有本书叫做《自然哲学的数学原理》&#xff0c;是牛顿写的&#xff0c;读完之后你就会感叹牛顿的厉害之处! 原文完整版PDF&#xff1a;https://pan.quark.cn/s/5d5eac2e56af 那玩意真的是人写出来的么… 现代教材把牛顿力学简化成三定律&#xff0c;当然觉得很简单。只有读了原…

【高等数学之不定积分】

一、什么是不定积分? 我们可以简单地从英文层面来基础剖析一下&#xff0c;什么是不定积分? 1.1、基本概念 小tips: 二、不定积分运算法则 三、常用积分公式 四、第一类换元积分法 4.1、定义 4.2、常用凑微分公式 4.3、小calculate 五、第二类换元积分法 5.1、定义 …