promise介绍和使用
这里不多说,直接看阮一峰老师的ES6入门书籍
promise类的实现
言归正传,此文全部都是以使用的层面来思考原理手写promise,会穿插一些promise使用的规则,可能会有点精简,具体使用规则请回到阮一峰老师的书籍。
promise类的使用
- Promise是一个类,在使用new关键字实例化的时候会传递一个执行器进去,执行器是同步代码会立即执行。
- Promise一共有三种状态,分别为成功(fulfilled)、失败(rejected)、和等待(pending),只可能是等待变为其他两种状态中的任意一种,一旦改变就定型,无法再次改变。
- resolve和rejecte用来更改promise状态。
- then方法判断状态,如果状态成功,调用成功回调函数,如果状态是失败则调用失败函数,then方法是被定义在原型对象中的。
- resolve方法会传入一个参数,这个参数用来修改成功或者失败后的原因,后期这个原因将会在then方法注册的回调函数中作为参数使用
正常使用promise的时候,我们是这样使用的:
new Promise((resolve,reject)=>{
resolve('ok')
// reject('fail')
})
我们会往promise构造函数塞一个函数进去作为执行器,执行器函数在promise实例化的时候马上被构造函数执行,这个函数有两个参数,一个resolve,一个reject,这两个参数都是方法,可以改变promise的状态,且promise有状态,所以还可以声明一个status作为它的状态。 以下,我们自己实现的promise类统一声明为MyPromise
//MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
constructor(executor){
executor(this.resolve,this.reject)
}
//初始化为准备状态
status = PENDING
//成功的原因
value = undefined
//失败的原因
reason = undefined
resolve = (value)=>{
//状态一旦改变就定型
if(this.status != PENDING) return
this.status = FULFILLED
//保存成功以后的值
this.value = value
}
reject = (reason)=>{
if(this.status != PENDING) return
this.status = REJECTED
//保存失败以后的值
this.reason = reason
}
then(successCallback,failCallback){
if(this.status == FULFILLED){
//成功则调用成功以后的回调
successCallback(this.value)
}else if(this.status == REJECTED){
//失败则调用失败后的回调
failCallback(this.reason)
}
}
}
//CommonJS模块方案导出
module.exports = MyPromise
//index.js
const MyPromise = require('./MyPromise')
new MyPromise((resolve,reject)=>{
resolve('ok')
}).then(res=>{
console.log(res)
})
用nodemon运行一下index.js
此时可以看到这个promise已经初具雏形了
Promise的异步执行
在刚才这个版本的promise,我们只是实现了promise类,但是我们常用的promise一般是在异步环境中执行,比如我们刚才这个版本的promise是无法在setTimeout中改变状态的
此时控制台并没有输出任何东西,表示then函数的成功回调并没有被执行,那么我们现在来实现一个支持异步模式的promise。
首先,思考一下,为什么不能异步执行。因为当你调用.then方法的时候,此时promise还是pending状态,两秒以后才是resolve状态。那么此时.then方法里面两个if都没有匹配到,所以此时我们要做的应该是在.then函数里面增加一个pending状态的判断,如果执行.then函数的时候promise是pending状态,此时就把成功回调和失败回调都储存起来,等resolve的时候再调用。这也是为什么很多地方使用.then的时候说是**“注册回调函数”** 的原因。
//MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
constructor(executor){
executor(this.resolve,this.reject)
}
//初始化为准备状态
status = PENDING
//成功的原因
value = undefined
//失败的原因
reason = undefined
//存储起来的回调
successCallback = undefined
failCallback = undefined
resolve = (value)=>{
//状态一旦改变就定型
if(this.status != PENDING) return
this.status = FULFILLED
//保存成功以后的值
this.value = value
//如果之前存储了回调函数则此时调用
this.successCallback && this.successCallback(this.value)
}
reject = (reason)=>{
if(this.status != PENDING) return
this.status = REJECTED
//保存失败以后的值
this.reason = reason
//如果之前存储了回调函数则此时调用
this.failCallback && this.failCallback(this.reason)
}
then(successCallback,failCallback){
if(this.status == FULFILLED){
//成功则调用成功以后的回调
successCallback(this.value)
}else if(this.status == REJECTED){
//失败则调用失败后的回调
failCallback(this.reason)
}else{
//pending状态 存储回调函数
this.successCallback = successCallback
this.failCallback = failCallback
}
}
}
//CommonJS模块方案导出
module.exports = MyPromise
可以看到此时是两秒后执行的打印,这里index.js代码就不贴了。
实现promise的.then方法的多次调用
我们此时的promise是可以多次调用.then方法的
但是在promise中异步改变状态是不行的
所以,我们要在注册回调的时候,存到数组里面去,在resolve或者reject中再把数组中的回调函数从第一个开始一个个执行
//MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
constructor(executor){
executor(this.resolve,this.reject)
}
//初始化为准备状态
status = PENDING
//成功的原因
value = undefined
//失败的原因
reason = undefined
//存储起来的回调
successCallback = []
failCallback = []
resolve = (value)=>{
//状态一旦改变就定型
if(this.status != PENDING) return
this.status = FULFILLED
//保存成功以后的值
this.value = value
//如果之前存储了回调函数则此时调用
while(this.successCallback.length){
this.successCallback.shift()(this.value)
}
}
reject = (reason)=>{
if(this.status != PENDING) return
this.status = REJECTED
//保存失败以后的值
this.reason = reason
//如果之前存储了回调函数则此时调用
while(this.failCallback.length){
this.failCallback.shift()(this.reason)
}
}
then(successCallback,failCallback){
if(this.status == FULFILLED){
//成功则调用成功以后的回调
successCallback(this.value)
}else if(this.status == REJECTED){
//失败则调用失败后的回调
failCallback(this.reason)
}else{
//pending状态 存储回调函数
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
}
}
//CommonJS模块方案导出
module.exports = MyPromise
promise的链式调用
promise是可以被链式调用的,then方法返回一个promise,这个promise的resolve的值就是上一个.then函数的返回值。 要实现这一点,首先我们得在.then函数中new一个promise,在执行回调函数的时候,把回调函数的返回值设为这个new出来的promise的resolve中,最后返回这个promise。
//MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
constructor(executor){
executor(this.resolve,this.reject)
}
//初始化为准备状态
status = PENDING
//成功的原因
value = undefined
//失败的原因
reason = undefined
//存储起来的回调
successCallback = []
failCallback = []
resolve = (value)=>{
//状态一旦改变就定型
if(this.status != PENDING) return
this.status = FULFILLED
//保存成功以后的值
this.value = value
//如果之前存储了回调函数则此时调用
while(this.successCallback.length){
this.successCallback.shift()(this.value)
}
}
reject = (reason)=>{
if(this.status != PENDING) return
this.status = REJECTED
//保存失败以后的值
this.reason = reason
//如果之前存储了回调函数则此时调用
while(this.failCallback.length){
this.failCallback.shift()(this.reason)
}
}
then(successCallback,failCallback){
let promise2 = new MyPromise((resolve,reject)=>{
if(this.status == FULFILLED){
//成功则调用成功以后的回调
let x = successCallback(this.value)
resolve(x)
}else if(this.status == REJECTED){
//失败则调用失败后的回调
let x = failCallback(this.reason)
reject(x)
}else{
//pending状态 存储回调函数
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
})
return promise2
}
}
//CommonJS模块方案导出
module.exports = MyPromise
此时已经链式调用成功,但是你会发现异步的情况链式调用并没有生效,别急,一步步来。
promise链式调用返回promise对象
如果promise的回调函数返回的不是普通值,很明显这里不能再用
let x = successCallback(this.value)
resolve(x)
来简单解决,需要分类讨论
//MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
constructor(executor){
executor(this.resolve,this.reject)
}
//初始化为准备状态
status = PENDING
//成功的原因
value = undefined
//失败的原因
reason = undefined
//存储起来的回调
successCallback = []
failCallback = []
resolve = (value)=>{
//状态一旦改变就定型
if(this.status != PENDING) return
this.status = FULFILLED
//保存成功以后的值
this.value = value
//如果之前存储了回调函数则此时调用
while(this.successCallback.length){
this.successCallback.shift()(this.value)
}
}
reject = (reason)=>{
if(this.status != PENDING) return
this.status = REJECTED
//保存失败以后的值
this.reason = reason
//如果之前存储了回调函数则此时调用
while(this.failCallback.length){
this.failCallback.shift()(this.reason)
}
}
then(successCallback,failCallback){
let promise2 = new MyPromise((resolve,reject)=>{
if(this.status == FULFILLED){
//成功则调用成功以后的回调
let x = successCallback(this.value)
resolvePromise(x,resolve,reject)
}else if(this.status == REJECTED){
//失败则调用失败后的回调
let x = failCallback(this.reason)
resolvePromise(x,resolve,reject)
}else{
//pending状态 存储回调函数
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
})
return promise2
}
}
function resolvePromise(x,resolve,reject){
if(x instanceof MyPromise){
//如果是promise
// x.then(value=>resolve(value),reason=>reject(reason))
//简写 .then方法会注册回调,resolve是一个函数,.then执行successCallback的时候会传递this.value作为实参,所以这里可以简写
x.then(resolve,reject)
}else{
//如果是普通值
resolve(x)
}
}
//CommonJS模块方案导出
module.exports = MyPromise
promise的then方法链式调用识别promise对象自返回
在promise的链式调用中,.then函数是会返回一个值的,这个值可能是普通值也可能是promise值,chrome给我提供的promise是不予许返回自己的,会提示循环调用错误。
同时,我们是可以在第一个then函数返回的对象中调用的时候捕获到这个错误的
那么在我们的promise中如何实现呢,首先,我们只需要判断第一个then函数的返回值是否跟then函数回调函数的返回值是否相等就可以了。
但是此时还有一个问题,resolvePromise函数执行时间是在new promise2的构造函数中,这个时候promise2是还没有定义的,那么有如何跟x相比较呢?
很简单,构造函数丢到宏任务代码(setTimeout)中执行就好了
//MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
//初始化为准备状态
status = PENDING
//成功的原因
value = undefined
//失败的原因
reason = undefined
//存储起来的回调
successCallback = []
failCallback = []
resolve = (value) => {
//状态一旦改变就定型
if (this.status != PENDING) return
this.status = FULFILLED
//保存成功以后的值
this.value = value
//如果之前存储了回调函数则此时调用
while (this.successCallback.length) {
this.successCallback.shift()(this.value)
}
}
reject = (reason) => {
if (this.status != PENDING) return
this.status = REJECTED
//保存失败以后的值
this.reason = reason
//如果之前存储了回调函数则此时调用
while (this.failCallback.length) {
this.failCallback.shift()(this.reason)
}
}
then(successCallback, failCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status == FULFILLED) {
setTimeout(() => {
//成功则调用成功以后的回调
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
}, 0);
} else if (this.status == REJECTED) {
//失败则调用失败后的回调
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} else {
//pending状态 存储回调函数
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
})
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
//如果第一个then函数的返回值跟then函数回调函数的返回值是否相等
reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
return
}
if (x instanceof MyPromise) {
//如果是promise
// x.then(value=>resolve(value),reason=>reject(reason))
//简写 .then方法会注册回调,resolve是一个函数,.then执行successCallback的时候会传递this.value作为实参,所以这里可以简写
x.then(resolve, reject)
} else {
//如果是普通值
resolve(x)
}
}
//CommonJS模块方案导出
module.exports = MyPromise
注意此时的setTimeout写在if判断逻辑内,如果包住整个构造器,就不会走到pending状态存储回调函数这一步,最后在p1.then的错误回调执行的时候打印的也是undefine
Promise异常处理
promise有可能在构造函数中发生错误,也有可能在成功回调或者失败回调中发生错误,所以这三部分我们都应该try catch一下。刚才我们只在成功的回调里面用setTimeOut处理了返回值是promise的情况,那么这里我们也顺便处理下失败回调的。
//index.js
const MyPromise = require('./MyPromise')
let promise = new MyPromise((resolve,reject)=>{
throw new Error("构造函数错误")
// reject("失败")
})
promise.then(res=>{
console.log(res)
},err=>{
console.log(err.message)
throw new Error("第一个错误回调函数返回的Error对象")
}).then(res=>{
console.log('第二个then:'+res)
},reason=>{
console.log('第二个reject:'+reason)
})
//MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
//初始化为准备状态
status = PENDING
//成功的原因
value = undefined
//失败的原因
reason = undefined
//存储起来的回调
successCallback = []
failCallback = []
resolve = (value) => {
//状态一旦改变就定型
if (this.status != PENDING) return
this.status = FULFILLED
//保存成功以后的值
this.value = value
//如果之前存储了回调函数则此时调用
while (this.successCallback.length) {
this.successCallback.shift()(this.value)
}
}
reject = (reason) => {
if (this.status != PENDING) return
this.status = REJECTED
//保存失败以后的值
this.reason = reason
//如果之前存储了回调函数则此时调用
while (this.failCallback.length) {
this.failCallback.shift()(this.reason)
}
}
then(successCallback, failCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status == FULFILLED) {
setTimeout(() => {
try {
//成功则调用成功以后的回调
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
} else if (this.status == REJECTED) {
//失败则调用失败后的回调
setTimeout(() => {
try {
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
} else {
//pending状态 存储回调函数
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
})
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
//如果第一个then函数的返回值跟then函数回调函数的返回值是否相等
reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
return
}
if (x instanceof MyPromise) {
//如果是promise
// x.then(value=>resolve(value),reason=>reject(reason))
//简写 .then方法会注册回调,resolve是一个函数,.then执行successCallback的时候会传递this.value作为实参,所以这里可以简写
x.then(resolve, reject)
} else {
//如果是普通值
resolve(x)
}
}
//CommonJS模块方案导出
module.exports = MyPromise
看一下此时的控制台输出
此时还没有完,因为构造器函数异步的情况还没有考虑,在.then函数中最后返回的是一个新的promise2,如果异步不考虑,这里将无法链式调用
明明在使用的时候,在第一个.then函数中返回了却无法链式调用。所以这里pending状态我们也要修改
//MyPromise.js
then(successCallback, failCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status == FULFILLED) {
setTimeout(() => {
try {
//成功则调用成功以后的回调
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
} else if (this.status == REJECTED) {
//失败则调用失败后的回调
setTimeout(() => {
try {
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
} else {
//pending状态 存储回调函数
this.successCallback.push(()=>{
setTimeout(() => {
try {
//成功则调用成功以后的回调
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
})
this.failCallback.push(()=>{
setTimeout(() => {
try {
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
})
}
})
return promise2
}
此时pending状态的异步处理完毕,但是要注意,这里pending状态.push的是一个没有形参的箭头函数,所以上面resolve和reject函数的调用需要改变下
resolve = (value) => {
//状态一旦改变就定型
if (this.status != PENDING) return
this.status = FULFILLED
//保存成功以后的值
this.value = value
//如果之前存储了回调函数则此时调用
while (this.successCallback.length) {
//去掉形参
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status != PENDING) return
this.status = REJECTED
//保存失败以后的值
this.reason = reason
//如果之前存储了回调函数则此时调用
while (this.failCallback.length) {
this.failCallback.shift()()
}
}
此时再看下控制台
将.then方法参数变为可选
我们平常调用.then的时候,有时候并不会在链式中全部都注册回调函数例如这样
但是此时,我们第三个回调函数并没有执行,所以我们在在自定义的promise中也要处理下可选参数情况:
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : (reason)=>{throw reason}
调用方式还是刚才那幅图的样子
Promise.all的实现
all方法也是我们常用的一个API,从使用层面,我们传入一个数组,然后返回一个已经改变了状态的promise,所以我们可以在后面链式调用.then函数,而且.then函数里面的回调函数的形参也是all方法返回的已解析完的数据。以下代码在Mypromise类中添加
//all肯定是个静态方法,因为可以用MyPromise.all调用,且实参是个数组
static all(array){
let result = []
function addRes(key,val){
result[key] = val
}
return new MyPromise((resolve,reject)=>{
//要循环遍历传入的数组
for(let i=0;i<array.length;i++){
let current = array[i]
if(current instanceof MyPromise){
//如果是promise
current.then(val=> addRes(i,val),reason=>reject(reason))
}else{
addRes(i,current)
}
}
resolve(result)
})
}
调用代码如下
const MyPromise = require('./MyPromise')
function p1(){
return new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve("success")
}, 2000);
})
}
function p2(){
return new MyPromise((resolve,reject)=>{
resolve("success2")
})
}
MyPromise.all(['1','2',p1(),p2(),'5']).then(res=>{
console.log(res)
})
让我们看看效果:
可以看到异步的p1在返回的数组中是一个空值,因为for循环是同步执行的,所以这里我们需要处理下,兼容下异步的情况:
//MyPromise.js
//all肯定是个静态方法,因为可以用MyPromise.all调用,且实参是个数组
static all(array){
return new MyPromise((resolve,reject)=>{
let result = []
let index = 0
function addRes(key,val){
result[key] = val
index ++
//兼容异步处理
if(index == array.length){
resolve(result)
}
}
//要循环遍历传入的数组
for(let i=0;i<array.length;i++){
let current = array[i]
if(current instanceof MyPromise){
//如果是promise
current.then(val=> addRes(i,val),reason=>reject(reason))
}else{
addRes(i,current)
}
}
})
}
我们再看下调用结果:
这样就达到期望值了。
Promise的resolve方法
Promise.resolve()方法也是我们常用的一个API,用来把传入的值变成一个已经resolve的promise对象,如果传入的就是一个promise对象,则原封不动的返回。这样就可以在后面链式调用.then函数了。既然可以用类名调用,那肯定也是一个static对象。
//MyPromise.js
//在类中添加下面的静态方法
static resolve(val){
if(val instanceof MyPromise){
return val
}else{
//若是普通值
return new Promise(resolve=>{
resolve(val)
})
}
}
看下效果图:
Promise.finally
‘finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。 finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。’以上来自阮一峰老师的教程,finally其实就是.then方法的特例。
//MyPromise.js
//在类中添加原型方法
finally(callback){
//因为在finally后面还可以继续链式调用,所以此处应该返回一个promise
//又因为.then方法本来就返回一个promise,且可以获得finally时的promise状态
return this.then((val)=>{
callback()
return val
},(reason)=>{
callback()
throw reason
})
}
//index.js
const MyPromise = require('./MyPromise')
function p1(){
return new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve("success")
}, 2000);
})
}
function p2(){
return new MyPromise((resolve,reject)=>{
resolve("success2")
})
}
p2().finally(()=>{
// console.log('finally')
throw new Error('finally err')
}).then(res=>{
console.log("resolve:" + res)
},reason=>{
console.log('reason:' + reason)
})
看一下调用效果
如果你在finally函数中返回p1呢?
这里直接走到p2的resolve去了,后面的.then也是根据p2的resolve状态来的。因为在finally函数中callback执行完以后就直接执行到return val这一句了,callback中的异步
setTimeout(() => {
resolve("success")
}, 2000);
并没有被finally返回,只是被挂起到异步队列中。那么此处我们可以用static的resolve方法来改写下,因为resolve方法刚好可以处理返回值是promise的情况
finally(callback){
//因为在finally后面还可以继续链式调用,所以此处应该返回一个promise
//又因为.then方法本来就返回一个promise,且可以获得finally时的promise状态
return this.then((val)=>{
return MyPromise.resolve(callback()).then(()=>val)
},(reason)=>{
return MyPromise.resolve(callback()).then(()=>{throw reason})
})
}
因为p1等待两秒才改变状态,所以两秒钟后输出console.log("resolve:" + res)
Promise.catch
Promise.catch方法其实就是.then(undefined,failCallback)的别名,所以实现可以如下:
catch(failCallback){
return this.then(undefined,failCallback)
}
效果如图:
完整实现代码:
//index.js
const MyPromise = require('./MyPromise')
function p1(){
return new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve("success")
}, 2000);
})
}
function p2(){
return new MyPromise((resolve,reject)=>{
// resolve("success2")
reject('fail')
})
}
p2().then(res=>{console.log("res:" + res)}).catch(res=>{
console.log('catch:'+res)
})
//MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
//初始化为准备状态
status = PENDING
//成功的原因
value = undefined
//失败的原因
reason = undefined
//存储起来的回调
successCallback = []
failCallback = []
resolve = (value) => {
//状态一旦改变就定型
if (this.status != PENDING) return
this.status = FULFILLED
//保存成功以后的值
this.value = value
//如果之前存储了回调函数则此时调用
while (this.successCallback.length) {
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status != PENDING) return
this.status = REJECTED
//保存失败以后的值
this.reason = reason
//如果之前存储了回调函数则此时调用
while (this.failCallback.length) {
this.failCallback.shift()()
}
}
then(successCallback, failCallback) {
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : (reason)=>{throw reason}
let promise2 = new MyPromise((resolve, reject) => {
if (this.status == FULFILLED) {
setTimeout(() => {
try {
//成功则调用成功以后的回调
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
} else if (this.status == REJECTED) {
//失败则调用失败后的回调
setTimeout(() => {
try {
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
} else {
//pending状态 存储回调函数
this.successCallback.push(()=>{
setTimeout(() => {
try {
//成功则调用成功以后的回调
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
})
this.failCallback.push(()=>{
setTimeout(() => {
try {
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
})
}
})
return promise2
}
finally(callback){
//因为在finally后面还可以继续链式调用,所以此处应该返回一个promise
//又因为.then方法本来就返回一个promise,且可以获得finally时的promise状态
return this.then((val)=>{
return MyPromise.resolve(callback()).then(()=>val)
},(reason)=>{
return MyPromise.resolve(callback()).then(()=>{throw reason})
})
}
catch(failCallback){
return this.then(undefined,failCallback)
}
//all肯定是个静态方法,因为可以用MyPromise.all调用,且实参是个数组
static all(array){
return new MyPromise((resolve,reject)=>{
let result = []
let index = 0
function addRes(key,val){
result[key] = val
index ++
if(index == array.length){
resolve(result)
}
}
//要循环遍历传入的数组
for(let i=0;i<array.length;i++){
let current = array[i]
if(current instanceof MyPromise){
//如果是promise
current.then(val=> addRes(i,val),reason=>reject(reason))
}else{
addRes(i,current)
}
}
})
}
static resolve(val){
if(val instanceof MyPromise){
return val
}else{
//若是普通值
return new Promise(resolve=>{
resolve(val)
})
}
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
//如果第一个then函数的返回值跟then函数回调函数的返回值是否相等
reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
return
}
if (x instanceof MyPromise) {
//如果是promise
// x.then(value=>resolve(value),reason=>reject(reason))
//简写 .then方法会注册回调,resolve是一个函数,.then执行successCallback的时候会传递this.value作为实参,所以这里可以简写
x.then(resolve, reject)
} else {
//如果是普通值
resolve(x)
}
}
//CommonJS模块方案导出
module.exports = MyPromise