写给前端开发者的「Promise备忘手册」

news2024/10/5 23:28:56

前言

大家好,我是HoMeTown,Promise想必大家都知道,在平时的开发工程中也经常会有用到,但是Promise作为ES6的重要特性,其实还拥有很多丰富的知识,本文面向比较初级一些的同学,可以帮你搞懂Promise到底做了什么,顺便起到一个备忘录的作用。

Promise?

Promsie中文直译承诺,其实也很好理解,就是无论这个异步任务最后的结果怎么样,我承诺会给你一个结果。

Promise在JavaScript中是一个处理异步代码的解决方案,他的出现解决了JavaScript异步编程回调地狱的问题(此处 que一下wxapi)。

Promise对象代表一个异步操作,有三种状态:pending(进行中) fulfilled(已成功) rejected(已失败)

一个Promsie实例必然处于上述的三个状态直译。

Promise的运行机制

当Promise被实例化后,其实例会处于pending状态,一般情况下,遇到以下操作,Promise的状态会被改变:

1.执行resolve
2.执行reject
3.出现报错

下面举个例子:

const p1 = new Promise((resolve, reject) => {
    resolve('成功')
    console.log('这里还能执行吗? -- p1')
    reject('失败')
    console.log('这里呢? -- p1')})
  console.log(p1,'p1')
  
  const p2 = new Promise((resolve, reject) => {
    reject('失败')
    resolve('成功')
    console.log('这里还能执行吗? -- p2')})
  console.log(p2, 'p2')
  
  const p3 = new Promise((resolve, reject) => {})
  console.log(p3, 'p3')
  
  const p4 = new Promise((resovle, reject) => {
    throw 'error'})
  console.log(p4, 'p4')
​
  const p5 = new Promise((resovle, reject) => {
    throw 'error'
    resolve('成功')
    reject('失败')})
  console.log(p5, 'p5')
​
  const p6 = new Promise('测试')
  console.log(p6, 'p6') 

执行结果如下:

通过上图中的执行结果我们可以发现:

1.new Promise 返回了一个Promise实例
2.传入Promise构造函数中的执行函数,会被立即执行,且拥有了两个参数resolve reject
3.resolve操作 之后 PromiseState(状态) 会变成 flufilled, PromiseResult 为 resolve的参数
4.reject操作 之后 PromiseState(状态) 会变成 rejected,PromiseResult 为 rejected的参数
5.报错之后 之后 PromiseState(状态) 会变成 rejected,PromiseResult 为 报错信息
6.如果没有执行resolve/reject,也没有出现报错,PromiseState(状态) 会保持 pending,PromiseResult 为 undefined
7.一旦执行resolve/reject,或者出现报错Promise会修改Promise实例的PromiseState & PromiseResult,后续的代码还会继续执行

Promise的使用

Promise作为一个构造函数可以被new关键字进行实例化,并在.then.catch分别取到成功和失败的结果。

p1.then(res => { console.log(res, '成功')}).catch(err => {console.log('失败', err)}) 

Promise封装请求器

function request({ method = "GET", url = "", data = {}, timeout = 10000 }) {
  const xhr = new XMLHttpRequest();
  return new Promise((resolve, reject) => {
    xhr.onreadystatechange = function () {
      if (xhr.readyState !== 4) return reject("xhr readyState error");
      if (xhr.timeout > timeout) return reject("request timout");
      if (xhr.status === 200) {
        resolve(JSON.parse(xhr.responseText));
    } else {
        reject(xhr.statusText);
    }
  };
    xhr.open(method, url);
    xhr.send(data);});
} 

测试请求器:

// 测试请求器
request({
  method: "GET",
  url: "https://api.apiopen.top/api/getHaoKanVideo?page=0&size=2",
}).then((res) => {
  console.log(res, "获取数据成功");
}); 

结果如下:

Promise原型上的方法

Promise.prototype.then

Promise.prototype具有then方法,也就是说,每一个Promsie实例对象都可以调用then方法得到Promsie成功的结果。

then方法的第一个参数是flufilled状态的回调函数,第二个参数是rejected状态的回调函数,举个栗子:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('good')
    reject('bad'); // 这里不会被执行}, 1000);
});
p1.then((res) => {
    console.log(res, "成功");},(err) => {
    console.log(err, "失败");}
);
​ 

执行结果如下:

Promise.prototype.catch

catch() 方法返回一个Promise,用捕捉指定错误并且处理错误。它的行为与调用Promise.prototype.then(_, onRejected) 相同,举个栗子:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("bad");}, 1000);
});
p1.catch(err => {
    console.log(err)
}) 

执行结果如下:

then链

有趣的是,then方法也返回了一个Promsie实例,那就意味着,可以继续执行.then进行下一次的结果获取,像这样:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("good");
    reject("bad");}, 1000);
});
p1.then((res) => {
  console.log(res, "then1");
}).then(res => {
    console.log(res, 'then2') // undefined 'then2'
}) 

then方法中,你可以通过return决定下一次的结果是什么:

  • 返回基本数据类型或者引用数据类型,下一次接受该数据,状态为flufilled,可继续.then* 返回一个Promsie* 状态为flufilled,可继续执行.then* 状态为pending,不会继续执行.then,直到当前Promise实例得到一个有效的状态* 状态为rejected,不会继续执行.then,直接走到.catch
  • 什么都没返回,执行.then,结果为undefined* 出现报错,直接走到.catch### Promise.prototype.finally

finally方法用于不管结果如何,都会执行的操作,可以避免相同的逻辑在then&catch重复写的情况,举个栗子:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("bad");}, 1000);
});
p1.then((res) => {
  console.log(res, "成功");
}).catch((err) => {
    console.log(err, "失败");}).finally(() => {
    console.log("不管成功不成功");});
​ 

执行结果如下:

Promise构造函数上的方法

Promise的prototype上也有一些函数可以使用,比如(race、all、any、race等):

Promise.resolve

Promise.resolve方法不是excutefunc上的resovle方法,而是原型上的方法,该方法接受一个参数,返回一个状态为fulfilled 的 Promise实例,如果参数为基本类型或者引用类型,则PromiseResult为传递进来的参数,举个栗子

const pstring = Promise.resolve('HoMeTowm')
console.log(pstring,'字符串 Promise实例')
​
const pnumber = Promise.resolve(123)
console.log(pnumber,'数字 Promise实例')
​
const pboolean = Promise.resolve(true)
console.log(pboolean,'布尔值 Promise实例')
​
const pobject = Promise.resolve({name: 'HoMeTowm'})
console.log(pobject,'对象 Promise实例')
​
console.log('......') 

执行结果如下:

const p1 = new Promise((resolve) => {
    resolve('Promise 实例: p1')
})
const ppromise = Promise.resolve(p1)
console.log(ppromise, 'Promise.resolve的实例:ppromise') 

执行结果如下:

如果没有传参数,返回PromiseResultundefined的Promise实例:

const pundefined = Promise.resolve()
console.log(pundefined) 

执行结果如下:

Promise.reject

Promise.reject方法相同,也会返回一个Promise实例,不同的是PromiseStatusrejectd,用上面的栗子进行测试:

const pstring = Promise.reject('HoMeTowm')
console.log(pstring,'字符串 Promise实例')
​
const pnumber = Promise.reject(123)
console.log(pnumber,'数字 Promise实例')
​
const pboolean = Promise.reject(true)
console.log(pboolean,'布尔值 Promise实例')
​
const pobject = Promise.reject({name: 'HoMeTowm'})
console.log(pobject,'对象 Promise实例')
​
console.log('......') 

执行结果如下:

Promise.all

Promise.all方法,可以发起并发请求,然后再所有Promise都脱离pending状态后,统一返回结果,接受一个数组作为参数,数组中的项为Promise实例(如果不是的话,传啥返回啥),返回一个Promise实例,PromiseResult每个实例对应的结果PromiseState所有的实例未脱离pending之前为pending,举个例子:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("p1 resolve执行");
    resolve("p1 的结果");}, 1000);
});
​
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("p2 resolve执行");
    resolve("p2 的结果");}, 2000);
});
​
const pnumber = 510
​
const pall = Promise.all([p1, p2, pnumber]);
console.log("promise.all 的结果未完成:", pall);
pall.then((res) => {
  console.log(res, "全部的结果");
  console.log("promise.all 的结果已完成:", pall);
});
​ 

执行结果如下:

数组中如果有一个失败,则返回失败的结果,只要失败了就返回!举个栗子:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('p1 还能执行')
    throw "哎呀,p1报错了";}, 1000);
});
​
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('p2 还能执行')
    resolve("p2 的结果");}, 2000);
});
​
const preject = Promise.reject("Promsie.reject 失败");
​
const pall = Promise.all([p2, p1, preject]);
console.log("promise.all 的结果未完成:", pall);
pall.then((res) => {
    console.log(res, "全部的结果");
    console.log("promise.all 的结果已完成:", pall);}).catch((err) => {
    console.log(err, "失败了 嘤嘤嘤");});
​ 

执行结果如下:

Promise.allSettled

Promise.allSettled用法与Promise.all相同,不同的是,Promise.allSettled不会因为有一个失败,就走到catch,而是会走到then,并告诉你,哪个失败了,那个成功了,举个栗子:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
     reject('p1 失败')}, 1000);
});
​
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2 成功");}, 2000);
});
​
​
const pall = Promise.allSettled([p2, p1, Promise.reject(1)]);
console.log("promise.allSettled 的结果未完成:", pall);
pall.then((res) => {
    console.log(res, "全部的结果");
    console.log("promise.allSettled 的结果已完成:", pall);}).catch((err) => {
    console.log(err, "失败了 嘤嘤嘤");});
​ 

执行结果如下:

Promise.race

Promise.race与其字面意思相同,竞速,即哪个先完成,就以哪个为结果,参数与Promise.all相同,举个栗子:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
     reject('p1 失败')}, 1000);
});
​
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2 成功");}, 2000);
});
​
​
const prace = Promise.race([p2, p1]);
​
prace.then(res => {
    console.log(res,'成功')
}).catch(err => {
    console.log(err, '失败')
}) 

执行结果如下:

Promise.any

Promise.any方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例,有一个子实例成功就算成功,全部子实例失败才算失败,返回AggregateError: All promises were rejected,举个栗子:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
     reject('p1 失败')}, 1000);
});
​
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2 成功");}, 2000);
});
​
​
const prace = Promise.any([p2, p1]);
​
prace.then(res => {
    console.log(res,'成功')
}).catch(err => {
    console.log(err, '失败')
}) 

执行结果如下:

p2改为reject之后,执行结果如下:

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

金庸群侠传3DUnity重置入门-Mods开发

金庸3DUnity重置入门系列文章 金庸3dUnity重置入门 - lua 语法 金庸3dUnity重置入门 - UniTask插件 金庸3dUnity重置入门 - Mods开发 金庸3dUnity重置入门 - Cinemachine 动画 金庸3dUnity重置入门 - 大世界实现方案 金庸3dUnity重置入门 - 素材极限压缩 (部分可能放到付…

[附源码]Nodejs计算机毕业设计基于web的社团管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

机器学习——01基础知识

机器学习——01基础知识 github地址:https://github.com/yijunquan-afk/machine-learning 参考资料 [1] 庞善民.西安交通大学机器学习导论2022春PPT [2] 周志华. 机器学习.北京:清华大学出版社,2016 [3] AIlearning 一、机器学习算法的应用 目前,机…

【Redis】集合Set和底层实现

文章目录Redis 集合(Set)Set简介常用命令应用场景共同关注实例整数集合整数集合介绍整数集合的升级哈希表哈希表的原理和实现Redis中的哈希表rehash渐进式rehashRedis 集合(Set) Set简介 Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以…

多维时序 | MATLAB实现GRU多变量时间序列预测

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab仿真内容点击👇 智能优化算法 …

c语言中fread,fgets等取文件字符的缓存空间小出现问题

一种奇怪现象 #include <stdio.h> #include <stdlib.h> #include<windows.h>int main(void){int i;printf("hello\n");fflush(stdout); //当没有这部刷新&#xff0c;hello会和end等到时间一起输出Sleep(2000); //windowsa.h中的Sleep&#…

某研究生不写论文竟研究起了算命?

起因 大约一个月前&#xff0c;在学校大病一场&#xff08;不知道是不是&#x1f411;了&#xff0c;反正在学校每天核酸没检测出来&#xff09;在宿舍休息了整整一周。当时因为发烧全身疼所以基本一直躺着刷刷视频。看了一周倪海厦老师讲的天纪&#xff0c;人纪感悟颇多&…

央企招聘:中国航空油料集团2023公开招聘

一、公司简介 中国航空油料集团有限公司&#xff08;以下简称“中国航油”&#xff09;成立于2002年10月11日&#xff0c;是以原中国航空油料总公司为基础组建的国有大型航空运输服务保障企业&#xff0c;是国内最大的集航空油品采购、运输、储存、检测、销售、加注为一体的航…

Spring Boot打成jar包后运行及配置文件的问题

Maven打包 因为Spring Boot项目内置Tomcat&#xff0c;所以可以打成一个jar包直接运行&#xff0c;而不必再需要安装Tomcat了。 如果用IDEA打包&#xff0c;还得先添加Artifacts&#xff1a; 然后再选择‘Main Class’ 显然比较麻烦&#xff0c;而且每次导入项目都得重新添加…

高频功率放大器工作原理总结(高频和低频功率放大器的区别)

高频功率放大器处在发射机的末级&#xff0c;主要作用是把高频已调拨信号进行功率放大&#xff0c;满足发送功率的要求&#xff0c;然后通过天线辐射到空间&#xff0c;保证一定区域接收机能够接收到信号电平。 高频功率放大器是通信系统中发送装置的组件&#xff0c;按照频带的…

【DOTS学习笔记】Cache层级结构与排队管理

目录前言如何理解L1,L2,L3级缓存的树形结构设计排队的烦恼现实中的排队烦恼计算机程序设计中的排队队列类型前言 本文是Metaverse大衍神君的《DOTS之路》系列课程的学习笔记 如何理解L1,L2,L3级缓存的树形结构设计 排队的烦恼 现实中的排队烦恼 这是一张关于排队的图&#xf…

论文速递:AAAI 2023 | 优图16篇论文速览,含多标签分类、姿态估计、目标检测、HOI、小样本学习等研究方向

近日&#xff0c;AAAI 2023&#xff08;Association for the Advancement of Artificial Intelligence&#xff09;国际先进人工智能协会公布了录用结果&#xff0c;本届会议共有8777篇投稿&#xff0c;录用1721篇&#xff0c;录用率19.6%。 AAAI是人工智能领域的主要学术组织之…

[go 语言学习笔记] 7天用Go从零实现分布式缓存GeeCache 「持续更新中」

说明 本文用于记录学习 go 语言过程中的笔记, 文中的代码都是在文本中敲出来的伪代码, 并不能直接运行, 如有需要可以参考原文链接. 本文的整体思路是对原系列教程阅读后的复盘. 关于本文参考的 学习教程 可以访问原教程链接: 7天用Go从零实现分布式缓存GeeCache 本文如有…

文本检测识别技术在合合信息的应用实务解决方案

合合信息保险行业全业务流程数字化解决方案 合合信息依托AI大数据&#xff0c;打造了保险行业全业务流程数字化解决方案&#xff1a;OCR智能分类识别文档、表格、卡证、票据、合同等&#xff0c;替代人工录入&#xff0c;图像智能质检优化&#xff0c;实现投保、核保、理赔、合…

(Matlab实现)基于蒙特卡洛模拟的大规模电动车充电模型

目录 摘要&#xff1a; 1电动车日行驶里程概率分布&#xff1a; 2.电动车充电起始时间概率分布&#xff1a; 3.大规模电动车充电行为蒙特卡洛建模&#xff1a; 3.1日行驶里程 3.2开始充电时间 3.3耗电量 3.4充电时间 3.5总充电负荷 4.不同规模的电动车的充电负荷曲线…

vue中vue-router安装与配置方法步骤详解

vue-router 是 vue.js 官方的路由插件&#xff0c;里面组件和 URL 的映射关系由 vue-route 帮我们管理。 在 vue-router 的单页面应用中&#xff0c;页面的路径的改变就是组件的切换。 第一步&#xff1a; 1.正常初始化项目的时候&#xff0c;会有个 vue-router 供我们选择。…

docker安装kafka、zookeeper

docker安装kafka、zookeeper 基于win10&#xff0c;docker desktop 基于linux也是一样的处理方式 (win10通过Docker搭建LNMP环境全流程)[https://blog.csdn.net/fendouweiqian/article/details/128062543] docker安装kafka、zookeeper 创建共享网络 为的是容器内可以通讯 …

vue-cli-3环境搭建和配置

一、vue 是单文件组件 之前注册组件有什么缺点 ? 1- 缺乏语法高亮 2-格式不好 3-没有专门的写css代码等等 参考 : vue > 工具 > 单文件组件 什么是单文件组件 &#xff1a;后缀为 .vue 的文件 单文件组件的三个组成部分 (代码块 : scaffold 自动提示) template (模…

21. 合理的模型初始化和激活函数

1. 让训练更加稳定 2. 让每层的方差是一个常数 以两个变量为例&#xff0c;均值为零可以让变量于自己的轴对称&#xff0c;那么在二维上整个变量分布就是中心对称&#xff0c;而方差则可以控制各个变量离原点的离散程度&#xff0c;那么就可以把二维变量看成限制在某个圈内。 在…

物联网开发笔记(61)- 使用Micropython开发ESP32开发板之控制3.2寸触摸屏的SD卡(续)

一、目的 这一节我们学习如何使用我们的ESP32开发板来控制3.2寸触摸屏的SD卡。 关键字&#xff1a;3.2寸SPI串口TFT液晶显示屏模块 ILI9341驱动 LCD触摸屏 240*320 XPT2046触摸屏芯片IC 二、环境 ESP32 3.2寸触摸屏SD卡模块 Thonny IDE 几根杜邦线 接线方法&#xff1a; …