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