【面试题】说说 Promise是什么?如何使用

news2024/11/17 19:34:18

 大厂面试题分享 面试题库

前端面试题库 (面试必备)   推荐:★★★★★

地址:前端面试题库

前言

本文主要介绍和总结Promise的作用、使用方式和其对应的一些方法,供大家参考学习,如有写的不准确的地方欢迎大家指出,相互学习,共同进步!

一. 什么是Promise?

JavaScript的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现

function requestData(url, successCallback, failtureCallback) {
  // 模拟网络请求
  setTimeout(() => {
    // 拿到请求的结果
    // url传入的是localhost, 请求成功
    if (url === "localhost") {
      // 成功
      successCallback('success')
    } else { // 否则请求失败
      // 失败
      failtureCallback("error")
    }
  }, 3000);
}

//执行请求
requestData("kobe", (res) => {
  console.log(res)
}, (err) => {
  console.log(err)
})
复制代码

但实际开发过程中有些情况需要多次调用服务器API,就会形成一个链式调用,比如为了完成一个功能,我们需要调用API1、API2、API3,依次按照顺序进行调用,这个时候就会出现回调地狱的问题,即嵌套层次深,不好维护,可读性差。这时候就需要用到Promise

二. Promise使用方式

Promise 对象的构造器(constructor)语法如下:

// 传入的这个函数, 被称之为 executor
// > resolve: 回调函数, 在成功时, 回调resolve函数
// > reject: 回调函数, 在失败时, 回调reject函数
let promise = new Promise(function(resolve, reject) { // executor });
复制代码

executor 最终将 promise 移至以下状态之一:

executor 只能调用一个 resolve 或一个 reject。一旦状态被确定下来,Promise的状态会被锁死,该Promise的状态是不可更改的。 

上方代码改写为Promise:

// request.js
function requestData(url,) {
  // 异步请求的代码会被放入到executor中
  return new Promise((resolve, reject) => {
    // 模拟网络请求
    setTimeout(() => {
      // 拿到请求的结果
      // url传入的是localhost, 请求成功
      if (url === "localhost") {
        // 成功
        resolve(success)
      } else { // 否则请求失败
        // 失败
        reject('error')
      }
    }, 3000);
  })
}

const promise = requestData("localhost")

//then方法是Promise对象上的一个方法:它其实是放在Promise的原型上的 Promise.prototype.then
promise.then((res) => {
  console.log("请求成功:", res)
}, (err) => { 
   console.log("请求失败:", err)
})

//等价于
promise.then((res) => {
  console.log("请求成功:", res)
}).catch(err => {//catch方法也是Promise对象上的一个方法:它也是放在Promise的原型上的 Promise.prototype.catch
console.log("请求失败:", err)
})
复制代码

当传入resolve不同的值的区别:

情况一:如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数;

情况二:如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态;

举例:

new Promise((resolve, reject) => {
  // pending -> fulfilled
  resolve(new Promise((resolve,reject)=>{
    setTimeout(()=>{resolve(111)},1000)
  }))
}).then(res => {
  console.log("res:", res) //111
}, err => {
  console.log("err:", err)
})
复制代码

情况三:如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据 then方法的结果来决定Promise的状态;

举例:

// 2.传入一个对象, 这个兑现有then方法
new Promise((resolve, reject) => {
  // pending -> fulfilled
  const obj = {
    then: function(resolve, reject) {
      // resolve("resolve message")
      reject("reject message")
    }
  }
  resolve(obj)
}).then(res => {
  console.log("res:", res)
}, err => {
  console.log("err:", err)//reject message
})
复制代码

三. Promise实例方法

1. then方法

Promise的状态变成fulfilled的时候,then方法可以多次调用(同理状态变成reject的时候,catch也可以被多次调用) :

onst promise = new Promise((resolve, reject) => {
  resolve("hahaha")
})

promise.then(res => {
  console.log("res1:", res)
})

promise.then(res => {
  console.log("res2:", res)
})

promise.then(res => {
  console.log("res3:", res)
})
复制代码

then方法本身也是有返回值的, 它的返回值是Promise,我们可以进行链式调用。

promise.then(res => {
  return "aaaaaa"
}).then(res => {
  console.log("res:", res) //aaaaaa
  return "bbbbbb"
})
复制代码

then方法返回的Promise到底处于什么样的状态呢?

then方法中的回调函数本身在执行的时候,那么它处于pending状态;

then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数;

then方法抛出一个异常时,那么它处于reject状态;

then传入不同值区别的同上方resolve相同,这边就不举例了,大家自己动手写一下。

2.catch 方法

catch方法也是会返回一个Promise对象的,所以catch方法后面可以继续调用then方法或者catch方法:

const promise = new Promise((resolve, reject) => {
  reject("111111")
})

promise.then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)//111111
  // throw new Error('hhhhhh')
  return "catch return value"
}).then(res => {
  console.log("res result:", res) //catch return value
}).catch(err => {
  console.log("err result:", err)  
})
复制代码

 

提示:把上方注释的throw方法打开,方法会取下方catch部分

3.finally 方法

finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象无论变成fulfilled还是reject状态,最终都会被执行的代码。

finally方法是不接收参数的,因为无论前面是fulfilled状态,还是reject状态,它都会执行

const promise = new Promise((resolve, reject) => {
  // resolve("resolve message")
  reject("reject message")
})

promise.then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
}).finally(() => {
  console.log("finally code execute")
})

复制代码

四. Promise类方法

1.Promise.resolve

用法相当于new Promise,并且执行resolve操作:

// 1.普通的值
 const promise = Promise.resolve({ name: "why" })
// 相当于
 const promise2 = new Promise((resolve, reject) => {
   resolve({ name: "why" })
 })
复制代码

2.Promise.reject

用法相当于new Promise,只是会调用reject:

const promise = Promise.reject("rejected message")
//相当于
const promise2 = new Promsie((resolve, reject) => {
  reject("rejected message")
})
复制代码

3.Promise.all

作用是将多个Promise包裹在一起形成一个新的Promise,新的Promise状态由包裹的所有Promise共同决定:

当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值 组成一个数组;

当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;

// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 1000);
})

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 2000);
})

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 3000);
})

// 需求: 所有的Promise都变成fulfilled时, 再拿到结果
// 意外: 在拿到所有结果之前, 有一个promise变成了rejected, 那么整个promise是rejected
Promise.all([p2, p1, p3, "aaaa"]).then(res => {
  console.log(res)
}).catch(err => {
  console.log("err:", err)
})
复制代码

3.Promise.race

如果有一个Promise有了结果,我们就希望决定最终新Promise的状态,那么可以使用race方法

// 只要有一个Promise变成fulfilled状态, 那么就结束
// 意外: 
Promise.race([p1, p2, p3]).then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
})

复制代码

后记

大厂面试题分享 面试题库

前端面试题库 (面试必备)   推荐:★★★★★

地址:前端面试题库

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

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

相关文章

Android 使用 jni Demo示例

Android 使用 jni Demo示例简介1. NDK的介绍1.1 NDK 简介1.2 NDK 特点2. JNI介绍2.1 JNI 简介2.2 为什么要有 JNI?3. NDK 与 JNI 的关系NDK下载及环境配置1. 使用Android studio SDK Manager下载2.配置NDK2.1 配置环境变量2.2 Android studio配置NDK示例Demo流程1.版…

RabbitMQ - 安装和使用

RabbitMQ - 安装和使用一. 安装二. RabbitMQ的简单使用2.1 创建交换机2.1.1 交换机类型2.1.2 持久化方式2.2 创建队列2.3 绑定交换机和队列2.4 SpringBoot整合2.5 另外一种监听写法一. 安装 一键安装: docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 …

rtl8221b+mcu,2.5g光纤收发器的开发备份

1、rtl8221b是一款2.5g的光电转换的phy 系统的构建如下 为了省成本,不用mac来对接其中的gmii接口直接接光模块 2、mdio和mdc由mcu的gpio来模拟,在csdn上有很多的文章来参考 mdio的参数如下 不想看英文可以参考下面的文章 MDIO(clause 22 与 clause 4…

Java基础之《netty(10)—Reactor三种模式》

一、单Reactor单线程模式 1、工作原理图 2、方案说明 (1)Select是前面I/O复用模型介绍的标准网络编程API,可以实现应用程序通过一个阻塞对象监听多路连接请求。 (2)Reactor对象通过Select监控客户端请求事件&#xf…

一元钱注册 chatGPT账号

文章目录打开 openai chatgpt 主页注册 chatGPT 账号找境外的电话号码激活账号查看服务价格账号注册充值成功参考视频 打开 openai chatgpt 主页 打开之前首先登录 vpn。但是使用 vpn 有可能还是会被告知 当前国家没有开放服务个人建议: 使用美国的 ip 地址我使用…

PIN TO PIN替代GM8775C|DSI转LVDS转换方案芯片CS5518|CS5518完全替代GM8775C

GM8775C 型 DSI 转双通道 LVDS 发送器产品主要实现将 MIPI DSI 转单/双通道 LVDS 功能,MIPI 支持 1/2/3/4 通道可选,最大支持 4Gbps 速率。LVDS 时钟频率最高 154MHz, 最大支持视频格式为 FULL HD(1920 x 1200) CS551…

网络安全观察报告

攻击类型分析 2018 年,主要的攻击类型 1 为 SYN Flood,UDP Flood,ACK Flood,HTTP Flood,HTTPS Flood, 这五大类攻击占了总攻击次数的 96%,反射类攻击不足 3%。和 2017 年相比&…

测评报告:文件导入哪家强?

文件导入哪家强? 引子 最近业务上遇到一个场景,需要将一个/多个文本文件导入到与其结构对应的表中。功能需求比较简单,大部分的关系数据库基本都支持这个功能。基于上面的场景把手头上的几款开源数据库和国产数据库的文件导入功能进行了性能对…

【通信基础】TTL、RS232、RS485

TTL1、TTL简介RS2321、RS232基本概念2、DB9串口定义及接线参考3、RS232经典电路4、特点RS4851、RS485简介2、特点3、传输距离4、经典电路5、传输差分电平信号TTL 1、TTL简介 TTL的英文全称是Transisor-Transisor Logic. 翻译过来就是晶体管与晶体管之间的逻辑电路。 TTL电平信…

78.【大二实训--《宿舍管理系统》】

大二实训--《宿舍管理系统》1.在JSP中,如果想要获取后端传过来的数据2.在Dao层我们用数据库的属性给实体类赋值的时候3.在一个Servlet中,如果想要使用多个Service4.字符串yyyy-mm-dd格式转换为Date型5.在设置实体类的时候,属性名开头一定要小…

IDEA创建JavaWeb项目并配置Tomcat

本文教给各位使用IDEA创建web项目,配置tomcat进行访问,好了,下面进入正题 IDEA分为社区版和企业版,区别在于,社区版免费,企业版收费,但有30天免费使用期,到期后会提示你进行激活&am…

MySQL 单表查询

1.简单查询 1.1 SELECT语句 SELECT [DISTINCT] * |字段名1,字段名2,... FROM 表名 [WHERE 条件表达式1] [GROUP BY 字段名 [HAVING 条件表达式2]] [GROUP BY 字段名 [ASC | DESC]] [LIMIT [OFFSET] 记录数]1.2 查询指定字段 SELECT 字段1,字段2,... F…

【深入理解 —— js闭包】

🧁个人主页:个人主页 ✌支持我 :点赞👍收藏🌼关注🧡 文章目录js闭包🎀 什么是闭包?🩰 执行上下文(执行环境)🍧解释闭包的含义&#x…

Linux 黑马

1.1虚拟机介绍1.2VMware Workstation虚拟化软件 下载CentOS; 5分钟教你下载安装VMware16虚拟机(含许可证密钥)【全免费VMware虚拟机 上集】_哔哩哔哩_bilibili 1.3远程链接Linux系统 &FinalShell 1.4拓展WSL(Ubuntu)环境 Win11>可选功能>…

愿你被这个世界温柔以待(第二十课)最优秀的仓库Gitee

愿你被这个世界温柔以待(第二十课)最优秀的仓库Gitee 在追梦的道路上 相信自己一定能变的更加优秀 看下面操作流程图:如果你觉自己的学习能力很强跟着下面的流程图片去走 图片教学 上传一份项目如何做 下面的是图片教学 看到上面的图片操作可能看不懂 Giteej基本操作命令行 初…

Photoshop简单案例(9)——利用PS去水印的四种方法

目录一、项目介绍二、简单水印2.1 水印原图2.2 去除步骤2.3 去除效果三、文件水印3.1 水印原图3.2 去除步骤3.3 去除效果3.4 拓展四、内容识别法4.1 水印原图4.2 去除步骤4.3 去除效果一、项目介绍 本文将介绍利用PhotoShop去水印的四种方法。 二、简单水印 2.1 水印原图 对…

我敢打赌,90%的测试人员都不理解Git

01 概念 1、Git本地有四个工作区域: 工作目录(Working Directory) 暂存区(Stage/Index) 资源库(Repository或Git Directory) git仓库(Remote Directory) 文件在这四…

深度学习设计模式(一):编写高质量代码的基础(多例子+代码)

学习如何编写高质量代码前言面向对象面向对象编程,面向对象编程语言面向对象分析 ,面向对象设计封装,抽象,继承,多态封装抽象继承多态面向对象比面向过程有哪些优势,面向过程过时了?什么是面向过…

MyBatisPlus入门

目录 概述 SpringBoot继承MyBatisPlus CRUD 新增 删除 修改 查询 条件构造器 全局配置 相关注解 ActiveRecord 插件 分页插件 防止全表删除插件 乐观锁插件 乐观锁插件的使用 逻辑删除 使用逻辑删除 扩展 自动填充 Sql注入器 代码生成器Generator 代码生成器MyBa…

Seata 分布式事务你懂吗?学习了大咖的笔记,公司说要给我涨薪 8K

分布式事务处理过程的-ID三组件模型: 关于事务的基本概念 Seata 是阿里开源的分布式事务解决方案中间件,对业务侵入小,在应用中 Seata 整体事务逻辑基于两阶段提交的模型,核心概念包含三个角色: TM:事务发…