原型上的方法
Promise.prototype.then
Promise.prototype.catch
这两个方法都在
JS个人学习——一个符合A+规范的Promise实现中写过。
包括下述resolvePromise方法都在这里写过。
Promise.prototype.finally
finally方法的作用于promise对象执行后,不管成功还是失败,都会执行finally的回调函数,并且这个回调函数没有参数,最后finally返回一个新的promise实例,它的状态跟之上一个promise实例的状态相同。
原理:
finally方法实际上就是补充一个正常的then方法,这个then方法两个参数都有传入,唯一不同的就是finally返回的promise实例的状态跟调用它的promise实例的状态是一致的,而直接用then后返回的promise实例的状态不一定跟调用它promise实例状态相同:
var promise1 = new Promise((resolve, reject) => {
reject('error')
})
var promise2 = promise1.then(res => {
}, reason => {
})
setTImeout(() => {
console.log(promise1) // Promise{<rejected>: 'error'}
console.log(promise2) // Promise{<fulfilled>: undefined}
})
var promise1 = new Promise((resolve, reject) => {
reject('error')
})
var promise2 = promise1.finally(() => {
})
setTimeout(() => {
console.log(promise1) // Promise{<rejected>: 'error'}
console.log(promise2) // Promise{<rejected>: 'error'}
})
根据上述代码可以看出用finally和then之间的一些区别,因此在finally实现的时候只要模拟正常链式调用then方法,并且补全它的两个参数,然后根据上一个promise实例的状态进行返回新实例。
简单来说,就是在finally中执行了一个方法,其他的都保持上一个promise实例的样子不变。
Promise.resolve('success').then(res => {
return res
})
.finally(() => {
// 回调函数内容
})
// finally的执行就跟加了下列代码差不多,只不过就是要将finally的回调函数放到resolve中执行
.then(value => {
return Promise.resolve().then(() => {
return value
})
}, reason => {
retutn Promise.resolve().then(() => {
throw reason
})
})
实现:
// finally只接受一个回调函数,因此只要传一个callback就行
Promise.prototype.finally = function (callback) {
return this.then((value) => {
/**
这里在Promise.resolve中执行callback
这里返回一个新的promise是为了让then中返回的promise的状态与其统一
*/
return Promise.resolve(callback()).then(() => {
return value;
});
}, (err) => {
return Promise.resolve(callback()).then(() => {
throw err;
});
});
}
对象上的方法
Promise.resolve()
Promise.resolve(value)方法返回一个以给定值解析后的Promise对象。
- 如果value是个thenable对象,返回的promise的状态会跟着thenable的状态保持一致。
- 如果value本身就是一个promise对象,那么就将其原封不动地返回。
- 其他情况下,直接返回成功状态的promise对象。
实现:
Promise.resolve = function (value) {
// 对应情况2
if (value instanceof Promise) {
return value
}
return new Promise((resolve, reject) => {
// 对应情况1
if (value && value.then && typeof value.then === 'function') {
// 用setTimeout保证x.then是异步执行
setTimeout(() => {
value.then(resolve, reject)
})
} else {
// 直接返回,对应情况3
resolve(value)
}
})
}
Promise.reject()
Promise.reject()方法与Promise.resolve()不同,只需直接将参数原封不动放到reject中作为后续方法的参数就行。
实现:
Promise.reject = function (reason) {
// 直接将reason放到reject中返回就行
return new Promise((resolve, reject) => {
reject(reason)
})
}
Promise.all()
Promise.all()需要一个由promise实例组合成数组作为参数,并将其包装成一个新的promise实例返回,并且成功和失败的返回值是不同的,成功的时候返回的是一个数组结果,而失败的时候则返回最先被reject的值。
使用方式:
var p1 = new Promise((resolve, reject) => { resolve('success1') })
var p2 = new Promise((resolve, reject) => { resolve('success2') })
var p3 = Promise.resolve('success3')
var result = Promise.all([p1, p2, p3])
console.log(result) // Promise {<fulfilled>: Arrary(3)}
var p1 = new Promise((resolve, reject) => { resolve('success1') })
var p2 = new Promise((resolve, reject) => { reject('error2') })
var p3 = Promise.resolve('success3')
var result = Promise.all([p1, p2, p3])
console.log(result) // Promise {<reject>: 'error2'}
其他说明:
- 如果传入的参数是一个空的可迭代对象,那么此promise对象回调完成(resolve),这种情况下是同步执行的,其他情况都是异步的。
- 如果传入的参数promises不包含任何promise,则将其值直接原封不动放到结果数组中返回。
- 参数promises中所有promise都执行完成或者其中有状态为'rejected'时,Promise.all执行完成
- 如果参数promises中有一个promise失败,那么Promise.all返回的promise对象的状态为'rejected',并且结果为失败的reason,此时返回的promise结果不是一个数组,而是promises中最先返回'rejected'状态的返回值
- Promise.all返回数组时,数组中对应的结果要与传入的promise顺序保持一致。
实现:
Promise.all = function (promises) {
// 返回一个promise对象
return new Promise((resolve, reject) => {
// 用index记录是否全部执行成功
var index = 0
// 用result,存放执行结果,并且最后执行完成时返回
var result = []
// 这里需要判断如果传入的promises为空数组,那么直接返回,对应情况1
if (promises.length === 0) {
return resolve(result)
}
// 遍历传入的参数,来获取每个promise的执行结果,这里的需要使用let,因为then方法的调用是异步的,
// 不使用let的话会导致之后then中的回调所用到的i都为相同值,用let创建块级作用域避免此问题
for (let i = 0; i < promises.length; i++) {
// 放到Promise.resolve()中执行是因为promises[i]有可能不是promise对象
Promise.resolve(promises[i]).then(value => {
/**
这里要使用result[i]来存值,以保证返回的结果的顺序跟传入的promise顺序相同,对应情况5,
因为这里then的调用是异步的,为了防止在异步状态下返回结果顺序不一致,因此不使用reslut.push(value)
*/
result[i] = value
// 通过index值判断是否全部执行完毕,如果执行完毕,那么将result作为参数执行resolve
if (++index == promises.length) {
resolve(result)
}
}, reason => {
/**
这里就是当promis执行时有一个是返回rejected状态时,
那就直接返回第一个失败的状态和结果,
因此不必像上面判断成功那样子来判断是否所有promise成功
*/
reject(reason)
})
}
})
}
测试代码:
var promise1 = new Promise((resolve, reject) => {
resolve('success1')
})
var promise2 = 66;
var promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'success2')
})
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values)
},(err)=>{
console.log(err)
});
var p = Promise.all([])
var p2 = Promise.all([2021, "wyt"])
console.log(p)
console.log(p2)
setTimeout(function(){
console.log('hello world')
console.log(p2)
})
Promise.race()
Promise.race()和Promise.all()一样是传入一个数组作为参数,并返回一个promise对象,但是它的状态是由第一个执行完成的promise状态来决定的,无论是fulfilled还是rejected。
使用方式:
var p1 = new Promise((resolve, reject) => { resolve('success1') })
var p2 = new Promise((resolve, reject) => { resolve('success2') })
var p3 = Promise.resolve('success3')
var result = Promise.race([p1, p2, p3])
console.log(result) // Promise {<fulfilled>: 1}
实现:
// 相对来说race的实现比all简单,不需要判断promises是否完全执行完成,
// 只要返回最快执行完成的promise实例的状态和结果就行。
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
if (promises.length === 0) {
resolve(promises)
}
Promise.resolve(promises[i]).then(value => {
resolve(value)
}, reason => {
reject(reason)
})
}
})
}
Promise.allSettled()
Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。
实现:
// Promise.allSettled()方法的实现跟Promise.all()大同小异,只有在一些细节上做一下处理就行
Promise.allSettled = function (promises) {
return new Promise((resolve, reject) => {
var index = 0
var result = []
if (promises.length === 0) {
return resolve(result)
}
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(value => {
// 细节一:跟Promise.all()方法不同的是需要将状态跟返回值放到对象中返回
result[i] = {
state: 'fulfilled',
value: value
}
if (++index == promises.length) {
resolve(result)
}
}, reason => {
result[i] = {
state: 'rejected',
reason: reason
}
// 细节二:在reject时也要判断promises是否全部执行完成
// allSettled永远都是返回的promise对象永远都是resolve
if (++index == promises.length) {
resolve(reason)
}
})
}
})
}
Promise.any()
Promise.any()方法跟Promise.all()方法刚好相反,只要有一个promise状态为成功就返回其对应的状态和结果
实现:
Promise.any = function (promises) {
return new Promise((resolve, reject) => {
var index = 0
var result = []
if (promises.length === 0) {
return resolve(result)
}
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(value => {
// 细节一:跟Promise.all()方法不同的是这里只要有一个执行成功就直接返回
resolve(value)
}, reason => {
result[i] = reason
// 细节二:在reject时判断是否全部都执行了reject,如果这样就要返回失败状态并且报错
if (++index == promises.length) {
reject(new Error('All promises were rejected'))
}
})
}
})
}