1.什么是Promise?
- Promise是一个有then方法的对象或函数
- thenable是一个具有then方法的对象或函数
- value是Promise成功状态的值,是resolve的参数,其值有undefined,Promise等
- reason是Promise失败状态的值,是reject的参数
- exception抛出异常
2.规范
Promise的状态
1. pending
- 初始状态,可改变
- 在resolve和reject执行之前都处于这个状态
- 在resolve执行中,状态从pending变为fulfilled,并且不再改变
- 在reject执行中,状态从pending变为rejected,并且不再改变
2. fulfilled
- 成功的状态
- resolve执行中会变为这个状态
3. rejected
- 失败的状态
- reject执行中会变为这个状态
小结:
- pending - resolve() -> fulfilled
- pending - reject() -> rejected
- pending转换为fulfillef或rejected之后就不再改变,并且pending只能转换为fulfilled或rejected
resolve方法
- 当前状态为pending时做以下操作
- 改变状态把pending状态变为fulfilled
- 改变当前的值,根据传递的参数作为当前的值
- 执行then中的onFulfilled回调集合
reject方法
- 当前状态为pending时做以下操作
- 改变状态,把pending状态变为rejected
- 改变当前值,根据传递的参数作为当前的值
- 执行then中onRejected回调集合
Promise的then方法
- 调用方式then(onFulfilled,onRejected)
- 具有两个参数分别是onFulfilled和onRejected,并且是可选的
- 返回一个新的Promise对象
onFulfilled回调函数
- 此方法必须是一个函数,如果不是一个函数则忽略掉(会默认创建一个新的函数)
- 当状态从pending变为fulfilled之前,此方法不应该被调用
- 当状态从pending变为fulfilled之后,此方法应该被调用,其参数为value
- 此方法只能被调用一次
onRejected回调函数
- 此方法必须是一个函数,如果不是一个函数则被忽略掉(会默认创建一个新的函数)
- 当状态从pending变为rejected之前,此方法不应该被调用
- 当状态从pending变为rejected之后,此方法应该被调用,其参数为reason
- 此方法只能被调用
onFulfilled和onRejected回调函数是在微任务队列中执行
- queueMicrotask(()=>{})可以当作微任务执行
then方法可以被同一个Promise调用多次
const p = new Promise()
p.then(fn1,err1)
p.then(fn2,err2)
p.then(fn3,err3)
- 如果状态变为fulfilled那么onFulfilled(fn)会按照then顺序执行fn1->fn2->fn3
- 如果状态变为rejected那么onRejected(err)会按照then顺序执行err1->err2->err3
then方法返回值
- 返回一个新的Promise对象
const p = new Promise().then(fn1,err1)
// 等同写法
const p1 = new Promise()
const p = p1.then(fn1, err1)
p1 === p // false
- 以上规范,就可以实现一个核心的Promise了,基本可以解决面试中的promise相关的题目
onFulfilled和onRejected执行结果处理
- 如果onFulfilled和onRejected执行结果为x,那么把x放入resolvePromise中处理
- 如果onFulfilled和onRejected执行结果其中有报错,那么直接通过then返回的新的Promise的reject执行
resolvePromise函数
resolvePromise(p,x,resolve,reject)
- p: then中新的promise对象
- x: onFulfilled和onRejected执行结果
- resolve: then中新的promise对象的resolve
- reject: then中新的promise对象的reject
如果p===x
- 那么直接抛出异常说明p和x不能为同一个实例
如果x为Promise对象
- x的fulfilled状态的结果value放在resolve中执行返回
- x的rejected状态的结果reason放在reject中执行返回
如果x是一个函数或对象
- let then = x.then
- then如果是一个函数,then.call(this)
- then如果是一个对象,resolve(then)
如果x是其他值
- resolve(x)
Promise.resolve()方法
- 直接通过构造器调用的方法属于静态方法,通过实例调用的方法属于实例方法
- 接收一个参数作
- 如果这个参数是Promise对象,那么直接返回这个值
- 如果不是Promise对象,那么返回一个新的Promise对象,把参数作为成功状态的值
Promise.reject()方法
- 接受一个参数
- 直接返回一个新的Promise,并且把这个参数作为失败状态的值
- 因此如果传递的是一个promise对象并且是失败的状态,那么直接得到的就是这个对象
const a = new Promise((res, rej) => { rej(22) })
Promise.reject(a).then(res => {
console.log(res)}, err => {
alert(err) // Promise对象,因为内部直接把参数作为失败的值返回
})
Promise.resolve(a).then(res => {
console.log(res)}, err => {
alert(err) // 22
})
Promise.all()方法
- 参数必须是一个数组,如果不是一个数组直接报错提示
- 数组中的值可以是Promise对象也可以不是
- 数组中的每一项都会被Promise执行
- 如果数组中有失败的状态,那么直接reject返回其值
- 如果数组中没有失败的状态,那么成功的值一定是按照数组的顺序返回一个数组
catch(fn)方法
- 接受一个函数作为参数
- 其内部其实调用了then(null,fn)方法,并且返回then执行的结果
- 因此catch返回的值也是一个新的Promise对象
根据规范代码实现
实现Promise的声明
// 实现的功能
const p = new Promise(() => {})
//实现的代码
// Promise是一个构造函数
class MPromise {
constructor(fn){
}
}
实现Promise的基本使用
// 实现的功能
const p = new Promise((resolve, reject) => {
resolve('成功')
})
//实现的代码
// 定义三种状态
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
// Promise是一个构造函数
class MPromise {
constructor(fn){
// 当前状态下的值
this.value = null
// 当前状态 初始状态为pending
this.status = PENDING
// fn同步执行,把resolve和reject传递进去
fn(this.resolve.bind(this), this.reject.bind(this))
}
// resolve的实现
resolve (val) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
// 改变状态
this.status = FULFILLED
// 改变值
this.value = val
// 执行回调集合,暂不处理,等到then完成之后再处理
}
}
// reject的实现
reject (reason) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
this.status = REJECTED
this.value = reason
// 执行回调集合,暂不处理,等到then完成之后再处理
}
}
}
实现then方法
// 实现功能
const p = new Promise((resolve, reject) => {
resolve('成功')
}).then(res => {
console.log(res) // 成功
}, err => {})
// 代码实现
// 定义三种状态
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
// Promise是一个构造函数
class MPromise {
constructor(fn){
// 当前状态下的值
this.value = null
// 当前状态 初始状态为pending
this.status = PENDING
// fn同步执行,把resolve和reject传递进去
fn(this.resolve.bind(this), this.reject.bind(this))
}
// resolve的实现
resolve (val) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
// 改变状态
this.status = FULFILLED
// 改变值
this.value = val
// 执行回调集合,暂不处理,等到then完成之后再处理
}
}
// reject的实现
reject (reason) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
this.status = REJECTED
this.value = reason
// 执行回调集合,暂不处理,等到then完成之后再处理
}
}
// then方法
then (onFulfilled, onRejected) {
// 如果回调函数不是一个函数则忽略。初始一个函数
onFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value }
onRejected = this.isFunction(onFulfilled) ? onRejected : (reason) => { throw reason }
// then方法返回一个新的promise
const p = new MPromise((resolve, reject) => {
// 根据当前状态判断具体执行成功回调还是失败回调
switch(this.status){
case FULFILLED: { // 如果是成功状态就执行成功的回调并把当前值传递进去
onFulfilled(this.value)
break;
}
case REJECTED: { // 如果是失败的状态就执行失败的回调把当前值传递进去
onRejected(this.value)
break;
}
}
})
return p
}
// 判断是否是一个函数
isFunction (fn) {
return typeof fn === 'function'
}
}
// 测试
const p = new MPromise((resolve, reject) => {
resolve('成功')
}).then(res => {
console.log(res) // 成功
}, err => {})
- 以上就是实现了一个同步的Promise,然而Promise主要是解决异步的回调,在then的switch只判断了成功和失败的状态,而pending状态没有处理,什么时候会是pending状态,pending状态是在Promise初始化的时候开始直到调用了成功或失败的方法之前都是处于pending状态,而成功和失败的方法的执行往往实在拿到结果之后才会执行。因此这个pending状态的时间段就是异步的,可能处于网络请求状态,可能处于延时状态等,因此根据pending就可以实现异步的回调执行,在pending状态需要把对应的回调存储起来,等到resolve或reject执行的时候再执行
// 主要代码实现
class MPromise {
constructor(fn){
// 定义两个数组分别用来存储pending时候的回调函数
// 注意这里为什么要用数组,根据规范的then下的第四点,是因为同一个Promise实例可以多次调用then
this.fulfilledList = []
this.rejectedList = []
...
}
// resolve的实现
resolve (val) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
...
// 执行回调集合
this.fulfilledList.forEach(cb => {
cb()
})
}
}
// reject的实现
reject (reason) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
...
// 执行回调集合
this.rejectedList.forEach(cb => {
cb()
})
}
}
// then方法
then (onFulfilled, onRejected) {
...
// then方法返回一个新的promise
const p = new MPromise((resolve, reject) => {
// 根据规范 成功和失败的回调是在微任务队列中执行
const onFulfilledMicroTask = () => {
queueMicrotask(() => {
onFulfilled(this.value)
})
}
const onRejectedMicroTask = () => {
queueMicrotask(() => {
onRejected(this.value)
})
}
// 根据当前状态判断具体执行成功回调还是失败回调
switch(this.status){
...
case PENDING: { // 如果是pending状态就需要把对应的回调存储起来
this.fulfilledList.push(onFulfilledMicroTask)
this.rejectedList.push(onRejectedMicroTask)
break;
}
}
})
return p
}
}
- 完整代码
// 实现功能
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 2000)
}).then(res => {
console.log(res) // 成功
}, err => {})
// 代码实现
// 定义三种状态
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
// Promise是一个构造函数
class MPromise {
constructor(fn){
// 定义两个数组分别用来存储pending时候的回调函数
// 注意这里为什么要用数组,根据规范的then下的第四点,是因为同一个Promise实例可以多次调用then
this.fulfilledList = []
this.rejectedList = []
// 当前状态下的值
this.value = null
// 当前状态 初始状态为pending
this.status = PENDING
// fn同步执行,把resolve和reject传递进去
fn(this.resolve.bind(this), this.reject.bind(this))
}
// resolve的实现
resolve (val) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
// 改变状态
this.status = FULFILLED
// 改变值
this.value = val
// 执行回调集合
this.fulfilledList.forEach(cb => {
cb()
})
}
}
// reject的实现
reject (reason) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
this.status = REJECTED
this.value = reason
// 执行回调集合
this.rejectedList.forEach(cb => {
cb()
})
}
}
// then方法
then (onFulfilled, onRejected) {
// 如果回调函数不是一个函数则忽略。初始一个函数
onFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value }
onRejected = this.isFunction(onFulfilled) ? onRejected : (reason) => { throw reason }
// then方法返回一个新的promise
const p = new MPromise((resolve, reject) => {
// 根据规成功和失败的回调是在微任务队列中执行
const onFulfilledMicroTask = () => {
queueMicrotask(() => {
onFulfilled(this.value)
})
}
const onRejectedMicroTask = () => {
queueMicrotask(() => {
onRejected(this.value)
})
}
// 根据当前状态判断具体执行成功回调还是失败回调
switch(this.status){
case FULFILLED: { // 如果是成功状态就执行成功的回调并把当前值传递进去
onFulfilledMicroTask(this.value)
break;
}
case REJECTED: { // 如果是失败的状态就执行失败的回调把当前值传递进去
onRejectedMicroTask(this.value)
break;
}
case PENDING: { // 如果是pending状态就需要把对应的回调存储起来
this.fulfilledList.push(onFulfilledMicroTask)
this.rejectedList.push(onRejectedMicroTask)
break;
}
}
})
return p
}
// 判断是否是一个函数
isFunction (fn) {
return typeof fn === 'function'
}
}
// 测试
const p = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 2000)
}).then(res => {
console.log(res) // 成功
}, err => {})
- 以上就基本实现了一个核心的Promise
- then方法可以有返回值,比如我们在then中返回一个Promise,一个基本数值等,而这个值的处理就在resolvePromise函数中
// 实现功能
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 2000)
}).then(res => {
console.log(res) // 成功
return new Promise(res => {
res('成功2')
})
}, err => {}).then(res => {
console.log(res) // 成功2
})
// 代码实现
// Promise是一个构造函数
class MPromise {
// then方法
then (onFulfilled, onRejected) {
// then方法返回一个新的promise
const p = new MPromise((resolve, reject) => {
// 根据规成功和失败的回调是在微任务队列中执行
const onFulfilledMicroTask = () => {
queueMicrotask(() => {
try{
const x = onFulfilled(this.value)
// 把返回的结果传递到resolvePromise
this.resolvePromise(p, x, resolve, reject)
}catch(e){
reject(e)
}
})
}
const onRejectedMicroTask = () => {
queueMicrotask(() => {
try{
const x = onRejected(this.value)
this.resolvePromise(p, x, resolve, reject)
}catch(e){
reject(e)
}
})
}
})
return p
}
// 在resolvePromise中对then中的回调结果进行处理
resolvePromise (p, x, resolve, reject) {
// 如果p和x相等需要抛错
if (p === x) {
return throw 'p和x不能是同一个Promise对象'
}
// 如果x是一个Promise
if (x instanceof MPromise) {
x.then(res => {
resolve(res)
},err => {
reject(err)
})
} else if (typeof x === 'function' || typeof x=== 'object') { // 如果是一个函数或对象
// 如果是null 直接resolve
if (x === null) {
return resolve(null)
}
try {
const then = x.then
// 根据规范 如果then是一个函数通过this调用,否则直接resolve返回
if (typeof then === 'function') {
return then.call(this)
} else {
return resolve(then)
}
} catch(e) {
return reject(e)
}
} else { // 其他值
return resolve(x)
}
}
}
- 完整代码
// 实现功能
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 2000)
}).then(res => {
console.log(res) // 成功
return new Promise(res => {
res('成功2')
})
}, err => {}).then(res => {
console.log(res) // 成功2
})
// 代码实现
// 定义三种状态
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
// Promise是一个构造函数
class MPromise {
constructor(fn){
// 定义两个数组分别用来存储pending时候的回调函数
// 注意这里为什么要用数组,根据规范的then下的第四点,是因为同一个Promise实例可以多次调用then
this.fulfilledList = []
this.rejectedList = []
// 当前状态下的值
this.value = null
// 当前状态 初始状态为pending
this.status = PENDING
// fn同步执行,把resolve和reject传递进去
fn(this.resolve.bind(this), this.reject.bind(this))
}
// resolve的实现
resolve (val) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
// 改变状态
this.status = FULFILLED
// 改变值
this.value = val
// 执行回调集合
this.fulfilledList.forEach(cb => {
cb()
})
}
}
// reject的实现
reject (reason) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
this.status = REJECTED
this.value = reason
// 执行回调集合
this.rejectedList.forEach(cb => {
cb()
})
}
}
// then方法
then (onFulfilled, onRejected) {
// 如果回调函数不是一个函数则忽略。初始一个函数
onFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value }
onRejected = this.isFunction(onFulfilled) ? onRejected : (reason) => { throw reason }
// then方法返回一个新的promise
const p = new MPromise((resolve, reject) => {
// 根据规成功和失败的回调是在微任务队列中执行
const onFulfilledMicroTask = () => {
queueMicrotask(() => {
try{ // try是因为promise中只要报错就走reject
const x = onFulfilled(this.value)
this.resolvePromise(p, x, resolve, reject)
}catch(e){
reject(e)
}
})
}
const onRejectedMicroTask = () => {
queueMicrotask(() => {
try{
const x = onRejected(this.value)
this.resolvePromise(p, x, resolve, reject)
}catch(e){
reject(e)
}
})
}
// 根据当前状态判断具体执行成功回调还是失败回调
switch(this.status){
case FULFILLED: { // 如果是成功状态就执行成功的回调并把当前值传递进去
onFulfilledMicroTask(this.value)
break;
}
case REJECTED: { // 如果是失败的状态就执行失败的回调把当前值传递进去
onRejectedMicroTask(this.value)
break;
}
case PENDING: { // 如果是pending状态就需要把对应的回调存储起来
this.fulfilledList.push(onFulfilledMicroTask)
this.rejectedList.push(onRejectedMicroTask)
break;
}
}
})
return p
}
// 判断是否是一个函数
isFunction (fn) {
return typeof fn === 'function'
}
// 在resolvePromise中对then中的回调结果进行处理
resolvePromise (p, x, resolve, reject) {
// 如果p和x相等需要抛错
if (p === x) {
throw 'p和x不能是同一个Promise对象'
}
// 如果x是一个Promise
if (x instanceof MPromise) {
x.then(res => {
resolve(res)
},err => {
reject(err)
})
} else if (typeof x === 'function' || typeof x=== 'object') { // 如果是一个函数或对象
// 如果是null 直接resolve
if (x === null) {
return resolve(null)
}
try {
const then = x.then
// 根据规范 如果then是一个函数通过this调用,否则直接resolve返回
if (typeof then === 'function') {
return then.call(this)
} else {
return resolve(then)
}
} catch(e) {
return reject(e)
}
} else { // 其他值
return resolve(x)
}
}
}
// 测试
const p = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 2000)
}).then(res => {
console.log(res) // 成功
return new MPromise(res => {
res('成功2')
})
}, err => {}).then(res => {
console.log(res) // 成功2
})
实现catch方法
- 下面开始实现Promise的catch方法,catch方法很简单,catch内部调用then方法把回调函数作为reject的参数执行
// 实现功能
const p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败')
}, 2000)
}).then(res => {
console.log(res)
}).catch(e => {
console.log(e) // 失败
})
// 代码实现
// Promise是一个构造函数
class MPromise {
...
catch (fn) {
// 直接返回then执行之后的结果, 因此catch得到的也是新的Promise
return this.then(null,fn)
}
}
- 接下来,实现Promise的静态方法,all, resolve, reject等
实现一个Promise.resolve(value)
- 如果value是一个Promise对象,直接返回
- 如果不是Promise对象,返回一个新的Promise对象,value作为成功状态的值
// 实现功能
Promise.resolve(21).then(res => {
console.log(res) // 21
})
// 代码实现
// Promise是一个构造函数
class MPromise {
...
static resolve (value) {
// 如果是一个Promise对象
if (value instanceof MPromise) {
return value
}
// 否则直接返回一个新的MPromise
return new MPromise((resolve,reject) => {
resolve(value)
})
}
}
实现一个Promise.reject方法
- 此方法很简单,直接返回一个新的promise对象,值作为失败的状态的值
// 实现功能
Promise.reject(0).then(res => {
console.log(res)
},err => {
console.log(err) // 0
})
// 代码实现
// Promise是一个构造函数
class MPromise {
...
static reject (reason) {
// 否则直接返回一个新的MPromise
return new MPromise((resolve,reject) => {
reject(reason)
})
}
}
- 因此Promise.reject和Promise.resolve有很大的区别,如果给这两个方法都传递一个Promise对象,那么Promise.resolve会返回这个Promise对象,而Reject会返回一个新的对象,最终Promise.resolve得到的结果是Promise对象resolve或reject之后的值,而Reject得到的是一个Promise对象
const p = new MPromise((resolve, reject) => {
resolve(1)
})
MPromise.resolve(p).then(res => {
console.log(res) // 1
})
MPromise.reject(p).then(res => {
console.log(res)
}, err => {
console.log(err) // MPromise对象
})
实现一个Promise.all方法
// 实现功能
const p1 = new Promise((resolve, reject) => {
resolve(1)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
},2000)
})
const p3 = 333
Promise.all([p1,p2,p3]).then(res => {
console.log(res) // [1, 2, 333]
})
// 代码实现
// Promise是一个构造函数
class MPromise {
...
static all (arr) {
// 如果参数不是一个数组就直接报错
if (!Array.isArray(arr)) {
throw Error('参数必须是一个数组')
}
return new MPromise((resolve, reject) => {
// 存储执行成功的结果
const result = []
// 定义一个计数变量,用来统计所有的成功是否都执行完毕
let count = 0
const len = arr.length
// 遍历数组
for (let i = 0; i < len; i++) {
MPromise.resolve(arr[i]).then(res => {
// 这里不能使用push,是因为all返回的成功值和参数的顺序为一致的
result[i] = res
count++
// 如果长度相等表示全部执行完毕,通过resolve返回
if (count === len) {
resolve(result)
}
}, err => {
reject(err) // 失败直接reject
})
}
})
}
}
- 注意点:
- all返回一个新的promise
- all中成功的回调获得到结果和传递的参数的顺序为一致的
- all中如果有一项抛错,就返回reject,但是参数中的都会被执行一次
- 完整代码
// 实现功能
const p1 = new Promise((resolve, reject) => {
resolve(1)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
},2000)
})
const p3 = 333
Promise.all([p1,p2,p3]).then(res => {
console.log(res) // [1, 2, 333]
})
// 代码实现
// 定义三种状态
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
// Promise是一个构造函数
class MPromise {
constructor(fn){
// 定义两个数组分别用来存储pending时候的回调函数
// 注意这里为什么要用数组,根据规范的then下的第四点,是因为同一个Promise实例可以多次调用then
this.fulfilledList = []
this.rejectedList = []
// 当前状态下的值
this.value = null
// 当前状态 初始状态为pending
this.status = PENDING
// fn同步执行,把resolve和reject传递进去
fn(this.resolve.bind(this), this.reject.bind(this))
}
// resolve的实现
resolve (val) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
// 改变状态
this.status = FULFILLED
// 改变值
this.value = val
// 执行回调集合
this.fulfilledList.forEach(cb => {
cb()
})
}
}
// reject的实现
reject (reason) {
// 只有在pending的时候才能改变状态和值
if (this.status === PENDING) {
this.status = REJECTED
this.value = reason
// 执行回调集合
this.rejectedList.forEach(cb => {
cb()
})
}
}
// then方法
then (onFulfilled, onRejected) {
// 如果回调函数不是一个函数则忽略。初始一个函数
onFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value }
onRejected = this.isFunction(onFulfilled) ? onRejected : (reason) => { throw reason }
// then方法返回一个新的promise
const p = new MPromise((resolve, reject) => {
// 根据规成功和失败的回调是在微任务队列中执行
const onFulfilledMicroTask = () => {
queueMicrotask(() => {
try{ // try是因为promise中只要报错就走reject
const x = onFulfilled(this.value)
this.resolvePromise(p, x, resolve, reject)
}catch(e){
reject(e)
}
})
}
const onRejectedMicroTask = () => {
queueMicrotask(() => {
try{
const x = onRejected(this.value)
this.resolvePromise(p, x, resolve, reject)
}catch(e){
reject(e)
}
})
}
// 根据当前状态判断具体执行成功回调还是失败回调
switch(this.status){
case FULFILLED: { // 如果是成功状态就执行成功的回调并把当前值传递进去
onFulfilledMicroTask(this.value)
break;
}
case REJECTED: { // 如果是失败的状态就执行失败的回调把当前值传递进去
onRejectedMicroTask(this.value)
break;
}
case PENDING: { // 如果是pending状态就需要把对应的回调存储起来
this.fulfilledList.push(onFulfilledMicroTask)
this.rejectedList.push(onRejectedMicroTask)
break;
}
}
})
return p
}
// 判断是否是一个函数
isFunction (fn) {
return typeof fn === 'function'
}
// 在resolvePromise中对then中的回调结果进行处理
resolvePromise (p, x, resolve, reject) {
// 如果p和x相等需要抛错
if (p === x) {
throw 'p和x不能是同一个Promise对象'
}
// 如果x是一个Promise
if (x instanceof MPromise) {
x.then(res => {
resolve(res)
},err => {
reject(err)
})
} else if (typeof x === 'function' || typeof x=== 'object') { // 如果是一个函数或对象
// 如果是null 直接resolve
if (x === null) {
return resolve(null)
}
try {
const then = x.then
// 根据规范 如果then是一个函数通过this调用,否则直接resolve返回
if (typeof then === 'function') {
return then.call(this)
} else {
return resolve(then)
}
} catch(e) {
return reject(e)
}
} else { // 其他值
return resolve(x)
}
}
static resolve (value) {
// 如果是一个Promise对象
if (value instanceof MPromise) {
return value
}
// 否则直接返回一个新的MPromise
return new MPromise((resolve,reject) => {
resolve(value)
})
}
static all (arr) {
// 如果参数不是一个数组就直接报错
if (!Array.isArray(arr)) {
throw Error('参数必须是一个数组')
}
return new MPromise((resolve, reject) => {
// 存储执行成功的结果
const result = []
// 定义一个计数变量,用来统计所有的成功是否都执行完毕
let count = 0
const len = arr.length
// 遍历数组
for (let i = 0; i < len; i++) {
MPromise.resolve(arr[i]).then(res => {
// 这里不能使用push,是因为all返回的成功值和参数的顺序为一致的
result[i] = res
count++
// 如果长度相等表示全部执行完毕,通过resolve返回
if (count === len) {
resolve(result)
}
}, err => {
reject(err) // 失败直接reject
})
}
})
}
}
// 测试
const p1 = new MPromise((resolve, reject) => {
resolve(1)
})
const p2 = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve(2)
},2000)
})
const p3 = 333
MPromise.all([p1,p2,p3]).then(res => {
console.log(res) // [1, 2, 333] 按照顺序输出
})
实现Promise.race方法
- race方法只要有一个执行就返回
// 实现功能
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
},1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
},2000)
})
const p3 = 333
Promise.race([p1,p2,p3]).then(res => {
console.log(res) // 333
})
// 代码实现
// Promise是一个构造函数
class MPromise {
...
static race (arr) {
// 如果参数不是一个数组就直接报错
if (!Array.isArray(arr)) {
throw Error('参数必须是一个数组')
}
return new MPromise((resolve, reject) => {
const len = arr.length
// 遍历数组
for (let i = 0; i < len; i++) {
MPromise.resolve(arr[i]).then(res => {
console.log(res)
resolve(result)
}, err => {
console.log(err)
reject(err) // 失败直接reject
})
}
})
}
}
- race方法中的参数都会被执行
const p1 = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
},2300)
})
const p2 = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve(2)
},2000)
})
const p4 = new MPromise((resolve, reject) => {
setTimeout(() => {
reject(4)
},1000)
})
MPromise.race([p1,p2,p4]).then(res => {
console.log(res) // 4
})
// 结果4 也会输出for循环中的console,分别是2、1
实现一个allSettled方法
Promise.allSettled([promise1, promise2])等待给定的所有的promise全部执行完成之后,不管是成功还是失败,最终会返回一个数组,数组中的每项都是根据输入的顺序执行之后的结果;如果传递的不是promise对象会通过Promise进行包装;
eg:
Promise.allSettled([1,2,3]).then(res => {
console.log(res) // [{status: 'fulfilled', value: 1},{status: 'fulfilled', value: 2},{status: 'fulfilled', value: 3}]
})
// 实现
class MPromise {
...
static allSettled (arr) {
// 如果参数不是一个数组就直接报错
if (!Array.isArray(arr)) {
throw Error('参数必须是一个数组')
}
return new MPromise((resolve, reject) => {
const len = arr.length
const result = []
// 遍历数组
for (let i = 0; i < len; i++) {
MPromise.resolve(arr[i]).then(res => {
result[i] = {
status: 'fulfilled',
value: res,
}
}, err => {
result[i] = {
status: 'rejected',
value: res,
}
}).finally(() => {
i === len - 1 && resolve(result)
})
}
})
}
}
MPromise.allSettled([MPromise.resolve(1), MPromise.reject(22)]).then(res => {
console.log(res) // [{status: 'fulfilled', value: 1},{status: 'rejected', value: 22}]
})
实现finally方法
finally不管成功还是失败都是执行,并且返回一个新的promise对象;
finally (callback) {
return this.then(data => {
return MPromise.resolve(callback()).then(() => {
return data
})
}, err => {
return MPromise.reject(callback()).then(() => { throw err })
})
}
相关面试题
- 面试题,打印出的Promise对象的状态分别是什么
const p = new MPromise((res,rej) => {
setTimeout(() => {
rej(1)
},3000)
}).then(null, err => {
console.log(p) //
})
setTimeout(() => {
console.log(p) //
},5000)
- 第一个输出的对象的状态应该是pending
- 第二个输出的对象的状态是fulfilled
- 解析:因此then返回的是一个新的Promise,而then回调的执行是在新Promise的resolve或reject之前,因此此时的状态还是pending
const onRejectedMicroTask = () => {
queueMicrotask(() => {
try{
// 这开始执行回调,而resolve或reject是在resolvePromise中执行,
// 因此此时的状态还是pending
const x = onRejected(this.value)
this.resolvePromise(p, x, resolve, reject)
}catch(e){
reject(e)
}
})
}
- 面试题,下面代码输出什么?
Promise.resolve(1).then(2).then(3).then(console.log)
解析:
-
Promise.resolve(1)执行之后,此时promise对象(标记为p1)的状态从pedding变为fulfilled,值为1;
-
再执行then(2)的时候,因为参数不是一个函数,内部会创建两个函数分别是成功和失败(微任务),返回一个新的promise对象,这里标记为p2;
-
又调用then(3),因为参数不是一个函数,内部会创建两个函数分别是成功和失败(微任务),返回一个新的promise对象,这里标记为p3;
-
又执行了then(console.log),传递了console.log这个函数(微任务)
-
执行栈执行完毕,此时开始执行微任务队列
-
因为p1的状态是fulfilled,因此会执行成功的函数并且把当前值1传递进去,函数把当前的值1返回,此时没有错误,所以p2的resolve(1)执行,此时p2的状态从pedding变为fulfilled,值为1;
-
因为p2的状态是fulfilled,因此会执行成功的函数并且把当前值1传递进去,函数把当前的值1返回,此时没有错误,所以p3的resolve(1)执行,此时p3的状态从pedding变为fulfilled,值为1;
-
因为p3的状态是fulfilled,因此会执行成功的函数console.log并且把当前值1传递进去,因此最后输出1
-
答案: 1
-
面试题:下面输出什么?
var a;
var b = new Promise((resolve,reject) => {
console.log('promise1')
setTimeout(() => {
resolve()
},1000)
}).then(() => {
console.log('promise2')
}).then(() => {
console.log('promise3')
}).then(() => {
console.log('promise4')
})
a = new Promise(async (resolve,reject) => {
console.log(a)
await b
console.log(a)
await a
resolve()
console.log('after')
})
console.log('end')
解析:
- 先执行第一个new Promise,其中的console.log('promise1')输出promise1,setTimeout宏任务一秒之后执行,返回一个Promise实例,此时的状态为pending;
- 执行第一个then,返回一个新的Promise对象p1,把成功的回调放入微任务队列中,此时的状态为pending;
- 执行第二个then,返回一个新的Promise对象p2,把成功的回调放入微任务队列中,此时的状态为pending;
- 执行第三个then,返回一个新的Promise对象p3,把成功的回调放入微任务队列中,此时的状态为pending;
- 第三个then之后完毕,b = p3,此时的状态为pending;
- 执行第二个new Promise,console.log(a)此时的new Promise还未执行完毕,因此a是undefined,所以输出undefined;
- 执行await b,要等待b的resolve执行,此时第二个new Promise执行完毕,返回一个promise对象pa,状态为pending
- 执行console.log('end'),输出end
- 一秒之后执行setTimeout(() => { resolve() },1000),第一个new Promise的状态变为fulfilled,执行第一个then的成功回调,输出promise2,p1的状态状态变为fulfilled;执行第二个then的成功回调,输出promise3,p2的状态状态变为fulfilled;执行第三个then的成功回调,输出promise4,p3的状态状态变为fulfilled;
- await b执行完毕,执行console.log(a),此时的a就是pa,状态为pending;
- 执行await a,此时a的状态为pending,因此一直处于等待状态,不再继续往下执行 答案: promise1,undefined,end,promise2,promise3,promise4,Promise对象状态为pending
- 面试题:
async function m1(){
return 1
}
async function m2(){
const n = await m1()
console.log(n)
return 2
}
async function m3(){
const n = m2()
console.log(n)
return 3
}
m3().then(res => {
console.log(res)
})
m3()
console.log(4)
解析:
- 执行 m3(),m3中执行了m2,m2中执行了m1,m1是async,因此此时返回promise对象p1,状态为fulfilled,成功的回调放入微任务队列中,m2返回一个promise对象p2,状态为pending,因此m2()执行完毕之后,console.log(n)n为P2状态为pending,m3执行完返回一个Promise对象p3,状态为fulfilled,成功的回调放入微任务队列中
- 再此执行m3(),m3中执行了m2,m2中执行了m1,m1是async,因此此时返回promise对象p1',状态为fulfilled,成功的回调放入微任务队列中,m2返回一个promise对象p2',状态为pending,因此m2()执行完毕之后,console.log(n)n为P2'状态为pending,m3执行完返回一个Promise对象p3',状态为fulfilled,成功的回调放入微任务队列中
- console.log(4) 输出4
- 执行微任务,p1的成功回调执行,await m1()返回1,因此输出console.log(n)为1,执行p3的回调console.log(res)输出3;执行p1'的成功回调执行,await m1()返回1,因此输出console.log(n)为1
- 答案:promise状态为pending,promise状态为pending, 4,1,3,1