大厂面试题分享 面试题库
前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
前言
本文主要介绍和总结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) }) 复制代码
后记
大厂面试题分享 面试题库
前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库