手写Promise源码

537 阅读15分钟

1. Promise类核心逻辑实现

(1)Promise就是一个类,在执行这个类的时候,需要传入一个执行器(回调函数)进去,执行器会立即执行。执行器有两个参数,resolve和reject 都是函数
(2)Promise中有三种状态 分别为 成功(flfilled)、失败(rejected)、等待(pending)
pending->flfilled/rejected,一旦状态确定就不可更改
(3)resolve和reject 函数是用来更改状态的
resolve: flfilled
reject: rejected
(4)then方法内部做的事情就是判断状态,如果状态是成功,调用成功的回调函数,如果状态是失败,调用失败的回调函数。then方法是被定义在原型对象当中的。
(5) then成功回调有一个参数,表示成功之后的值。then失败回调有一个参数,表示失败之后的原因。

let p = new Promise((resolve,reject)=>{
    resolve('成功')
    reject('失败')
})
p.then(value => { }, reason => { })
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {//constructor接收执行器,立即执行
        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)
        }
    }
}

let p = new MyPromise((resolve, reject) => {
    resolve('成功')
    reject('失败')
})
p.then(value => {
    console.log(value) //成功
}, reason => {
    console.log(reason)
})

2. 在Promise类中加异步逻辑

上面没有考虑异步情况,下面加入

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {//constructor接收执行器,立即执行
        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(value)
    }
    reject = reason => {
        if (this.status !== PENDING) return
        this.status = REJECTED
        this.reason = reason
        //判断失败回调是否存在存在就调用
        this.failCallback && this.failCallback(reason)
    }
    then(successCallback, failCallback) {
        //判断状态
        if (this.status === FULFILLED) {
            successCallback(this.value)
        } else if (this.status === REJECTED) {
            failCallback(this.reason)
        } else {
            //将成功回调和失败回调存储起来
            this.successCallback = successCallback;
            this.failCallback = failCallback
        }
    }
}

let p = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('成功')
        // reject('失败')
    }, 2000)
})

p.then(value => {
    console.log(value) //等待2s后输出成功!
}, reason => {
    console.log(reason)
})

解释:从上到下依次执行,new MyPromise创建MyPromise实例对象,此时执行器会立即执行。但是内部是一个setTimeout,执行器执行时发现内部是一个异步代码,主线程执行时,是不会等待异步代码执行执行完成之后再执行的。而是会立即执行。当主线程当中的代码执行完成之后再去执行异步代码。所以then会马上得到执行。then执行时先去判断status状态,此时一定是pending等待状态。我们再then中没有判断pending状态,去添加!因为不知道具体是成功还是失败,所以将两种状态存起来,当分别调用时候去判断,来返回到底是成功还是失败

3. 实现then方法多次调用添加多个处理函数

同一个promise对象下面的then方法是可以被多次调用的,当这个状态变成成功或者失败时,他对应的这个回调函数是要依次调用的。
(1)同步时候在判断时已经有状态了,调用其对应的回调函数就可以了
(2)异步时候需要把这些回调状态都存储起来,当状态变成成功或者失败时候,再通过循环依次调用回调函数

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) { //while循环当数组长度不等于0时,证明有回调函数
            this.successCallback.shift()(this.value) //从前往后执行,从数组当中删除值
        }
    }
    reject = reason => {
        if (this.status !== PENDING) return
        this.status = REJECTED
        this.reason = reason
        //判断失败回调是否存在存在就调用
        while (this.failCallback.length) { //while循环当数组长度不等于0时,证明有回调函数
            this.failCallback.shift()(this.reason) //从前往后执行
        }
    }
    then(successCallback, failCallback) {
        if (this.status === FULFILLED) {
            successCallback(this.value)
        } else if (this.status === REJECTED) {
            failCallback(this.reason)
        } else {
            //将成功回调和失败回调存储起来
            this.successCallback.push(successCallback);
            this.failCallback.push(failCallback)
        }
    }
}

let p = new MyPromise((resolve, reject) => {
    //同步成功测试
    // resolve('成功')
    //同步失败测试
    // reject('失败。。')
    //异步成功测试
    setTimeout(() => { resolve('成功..') }, 2000)
    //异步失败测试
    //setTimeout(() => { reject('失败。。') }, 2000)
})
p.then(value => {
    console.log(1, value)//2s后输出 1 成功..
}, reason => {
    console.log(reason)
})
p.then(value => {
    console.log(2, value)//2s后输出 2 成功..
}, reason => {
    console.log(reason)
})

4. 实现then方法的链式调用(一)

(1) 实现then方法的链式调用--每一个then方法都返回一个promise对象,这样才可以链式调用then

class MyPromise {
   //此处省略...
    then(successCallback, failCallback) {
    //在then方法中创建 promise对象,最后return返回
        let promise2 = new MyPromise(() => {//放到执行器中,立即执行
            if (this.status === FULFILLED) {
                successCallback(this.value)
            } else if (this.status === REJECTED) {
                failCallback(this.reason)
            } else {
                //将成功回调和失败回调存储起来
                this.successCallback.push(successCallback);
                this.failCallback.push(failCallback)
            }
        })
        return promise2
    }
}

(2) 实现如何把上一个then方法的返回值,传递给下一个then方法的回调函数

class MyPromise {
   //此处省略...
    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) {
                failCallback(this.reason)
            } else {
                //将成功回调和失败回调存储起来
                this.successCallback.push(successCallback);
                this.failCallback.push(failCallback)
            }
        })
        return promise2
    }
}
let p = new MyPromise((resolve, reject) => {
    //同步成功测试
    // resolve('成功')
    //异步成功测试
    // setTimeout(() => { resolve('成功..') }, 2000)
})

p.then(value => {
    console.log(1, value)
    return 100
}, reason => {
    console.log(1, reason)
}).then(value => {
    console.log(2, value)
}, reason => {
    console.log(2, reason)
})
//同步成功测试
// 1 "成功"; 2 100
//异步成功测试
// (2s后输出) 1 "成功"; 【此处异步处理有误,请看《捕获错误及then链式调用其他状态代码补充--处理异步代码部分》】

5. 实现then方法的链式调用(二)

then方法返回的可以是一个普通值,也可以是一个promise对象。如果返回的是一个普通值,我们可以直接调用resove方法把这个普通值传递给下一个promise对象。如果返回的是一个promise对象,我们要先去查看这个返回的promise对象他的状态,如果这个状态是成功的,我们要去调用resolve方法,把这个成功的状态传递给下一个promise对象,如果这个状态是失败的,我们要去调用reject方法,把这个失败的状态传递给下一个promise对象。

(1) 判断x的值是普通的值还是promise对象 (2) 如果是普通值 直接调用resolve (3) 如果是promise对象 查看promise对象返回的结果 (4) 再根据promise对象返回的结果 决定调用resolve 还是 reject

class MyPromise {
   //此处省略...
    then(successCallback, failCallback) {
        let promise2 = new MyPromise((resolve, reject) => {//放到执行器中,立即执行
            if (this.status === FULFILLED) {
                let x = successCallback(this.value)
                resolvePromise(x, resolve, reject)//普通的值还是promise对象到外面处理
            } else if (this.status === REJECTED) {
                failCallback(this.reason)
            } else {
                //将成功回调和失败回调存储起来
                this.successCallback.push(successCallback);
                this.failCallback.push(failCallback)
            }
        })
        return promise2
    }
}
function resolvePromise(x, resolve, reject) {//处理普通的值还是promise对象情况
    if (x instanceof MyPromise) { //判断x是不是new MyPromise这个类的实例
        // x.then(value => resolve(value), reason => reject(reason))
        x.then(resolve, reject)//x是promise对象,去查看他的状态并把他的状态传递给下一个promise对象
    } else { //普通值
        resolve(x)
    }
}
let p = new MyPromise((resolve, reject) => {
    //同步成功测试
    // resolve('成功')
})
function other() { //测试用
    return new MyPromise((resolve, reject) => {
        resolve('other')
    })
}
p.then(value => {
    console.log(1, value)
    return other()
}, reason => {
    console.log(1, reason)
}).then(value => {
    console.log(2, value)
}, reason => {
    console.log(2, reason)
})//1 "成功"; 2 "other"

6. then方法链式调用识别Promise对象自返回

then方法返回的可以是一个promise对象。但是有一种情况是例外的。在then方法的返回中是不能返回当前这个then方法他所返回的这个promise对象的,如果说在这个地方返回了他所返回的这个promise对象,这个时候就发生了promise对象循环调用,程序是不允许的。

var promise = new Promise((resolve, reject) => resolve(100))
var p1 = promise.then(value => {
    console.log(value)
    return p1
})//100 Error:Chaining cycle detected for promise #<Promise>
p1.then(() => { }, (reason) => console.log(reason.message))//100 Chaining cycle detected for promise #<Promise>

我们自己写的MyPromise中判断返回的promise2和保存成功回调的x是不是相等,如果相等就证明回调了自己,那么就把他放到reject错误中

class MyPromise {
   //此处省略...
    then(successCallback, failCallback) {
        let promise2 = new MyPromise((resolve, reject) => {
        //promise2只有在new MyPromise执行完才能获取到,想要获取需要把代码变成异步,让所有同步代码先去执行完成,执行完成promise2肯定就有了,然后在去执行异步代码
            if (this.status === FULFILLED) {
                setTimeout(() => { //不是为了延迟,只是为了异步,这部分代码会在所有同步代码执行完后才会执行
                    let x = successCallback(this.value)
                    resolvePromise(promise2, x, resolve, reject)
                }, 0)
            } else if (this.status === REJECTED) {
                failCallback(this.reason)
            } else {
                this.successCallback.push(successCallback);
                this.failCallback.push(failCallback)
            }
        })
        return promise2
    }
}
function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))//return 阻止代码向后执行
    }
    if (x instanceof MyPromise) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}
let p = new MyPromise((resolve, reject) => {
    resolve('成功')
})
let p1 = p.then(value => {
    console.log(1, value)
    return p1
}, reason => {
    console.log(reason.message)
})
p1.then(value => {
    console.log(value)
}, reason => {
    console.log(reason.message)
})
//1 "成功" ;Chaining cycle detected for promise #<Promise>

7. 捕获错误及then链式调用其他状态代码补充

(1)捕获执行器错误--当执行器当中的代码在执行的过程中发生错误,我们让promise变成失败状态,即then的第二个参数捕获

class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }

    }
   //此处省略...
}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
let p = new MyPromise((resolve, reject) => {
    //抛出错误
    throw new Error('executor error')
})
let p1 = p.then(value => {
    console.log(1, value)
}, reason => {
    console.log(reason.message) //executor error
})

(2)如果回调函数在执行过程中报错了 那么这个错误我们也要捕获到--如果回调函数在执行过程中报错了,这个错误要在下一个then方法当中捕获到

class MyPromise {
   //此处省略...
    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 (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                failCallback(this.reason)
            } else {
                this.successCallback.push(successCallback);
                this.failCallback.push(failCallback)
            }
        })
        return promise2
    }
}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
let p = new MyPromise((resolve, reject) => {
    resolve('成功')
})
let p1 = p.then(value => {
    console.log(1, value) //1 "成功"
    throw new Error('then error')
}, reason => {
    console.log(reason.message)
})
p1.then(value => {
    console.log(value)
}, reason => {
    console.log(999)//999
    console.log(reason.message)//then error
})

当前我们在处理then方法链式调用的时候只处理了成功的状态,状态失败和异步代码都没有处理

  • 处理状态失败
class MyPromise {
   //此处省略...
    then(successCallback, failCallback) {
        let promise2 = new MyPromise((resolve, reject) => {//放到执行器中,立即执行
            if (this.status === FULFILLED) {
               //此处省略...
            } else if (this.status === REJECTED) {
                setTimeout(() => { 
                    try {
                        let x = failCallback(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else {
                //此处省略...
            }
        })
        return promise2
    }
}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
let p = new MyPromise((resolve, reject) => {
    reject('失败。。')
})
let p1 = p.then(value => {
    console.log(1, value)
}, reason => {
    console.log(reason)
    return 10000 //失败回调中返回普通值或者promise,会跑到下一个then的回调里(return 成功会返回成功回调,return 失败会返回失败回调)
})
p1.then(value => {
    console.log(value) //10000
}, reason => {
    console.log(999)
    console.log(reason.message)
})
  • 处理异步代码
class MyPromise {
   //此处省略...
   resolve = value => {
        //此处省略...
        while (this.successCallback.length) {
            this.successCallback.shift()()//此时调用的成功或者失败函数里面 就不需要传递值了
        }
    }
    reject = reason => {
       //此处省略...
        while (this.failCallback.length) { 
            this.failCallback.shift()()//此时调用的成功或者失败函数里面 就不需要传递值了
        }
    }
    then(successCallback, failCallback) {
        let promise2 = new MyPromise((resolve, reject) => {//放到执行器中,立即执行
            if (this.status === FULFILLED) {
               //此处省略...
            } else if (this.status === REJECTED) {
                //此处省略...
            } else {
                //直接把成功或者失败回调push在数组当中,我们没办法对上面情况(try-catch)进行处理,所以push一个函数去处理成功或者失败回调
                //此时调用的成功或者失败函数里面 就不需要传递值了
                this.successCallback.push(() => {
                    setTimeout(() => { //不是为了延迟,只是为了异步,这部分代码会在所有同步代码执行完后才会执行
                        try {
                            let x = successCallback(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                });
                this.failCallback.push(() => {
                    setTimeout(() => { //不是为了延迟,只是为了异步,这部分代码会在所有同步代码执行完后才会执行
                        try {
                            let x = failCallback(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
            }
        })
        return promise2
    }
}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}

let p = new MyPromise((resolve, reject) => {
    setTimeout(() => { resolve('成功..') }, 2000)
})
let p1 = p.then(value => {
    console.log(1, value) //1 '成功..'
    return 'aaa'
}, reason => {
    console.log(reason) 
})
p1.then(value => {
    console.log(value) //'aaa'
}, reason => {
    console.log(999)
    console.log(reason.message)
})

8. 将then方法的参数变成可选参数

调用then方法时候我们可以传递0、1、2个参数

var promise = new Promise((resolve, reject) => resolve(100))
promise.then().then().then(value => console.log(value)) //100

在then方法内部判断then有没有参数,如果没有我们就给他补上一个参数,形成下面这样,进行传递

promise.then(value =>value ).then(value =>value).then(value => console.log(value))
class MyPromise {
   //此处省略...
    then(successCallback, failCallback) {
        //判断是否有参数,如果有就传递,没有就把数据向下传递
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
        let promise2 = new MyPromise((resolve, reject) => {
           //此处省略...
        })
        return promise2
    }
}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
let p = new MyPromise((resolve, reject) => {
    //同步成功测试
    resolve('成功')
    //同步失败测试
    //reject('失败。。')
})
p.then().then().then(value => {
    console.log(value)//成功 测试成功时候
}, reason => {
    console.log(reason)//失败。。 测试失败时候
})

当我们调用then时候可以不传递参数,promise状态会依次向后传递直到传递给有回调的地方

9. Promise.all方法的实现

function mP1() {
    return new Promise((resolve) => {
        setTimeout(() => resolve('mP1'), 2000)
    })
}
function mP2() {
    return new Promise((resolve) => {
        resolve('mP2')
    })
}
Promise.all(['a', 'b', mP1(), mP2(), 'c']).then(res => console.log(res))
//(2s后输出)["a", "b", "mP1", "mP2", "c"]

正常不用Promise.all的时候,先得到mP2(有延迟执行) 在得到mP1
Promise.all允许我们调用顺序得到异步代码结果顺序,Promise.all返回一个promise Promise.all接收一个数组作为参数,里面的promise都是成功就返回成功数组,否则返回错误

class MyPromise {
   //此处省略...
    static all(array) {
        let result = []
        function addData(key, value) {
            result[key] = value
        }
        return new MyPromise((resolve, reject) => {
            //循环这个数组,如果是普通值就直接放入结果数组,如果是promise对象,先去执行promise对象,把结果放入结果数组
            for (let i = 0; i < array.length; i++) {
                let current = array[i]
                if (current instanceof MyPromise) {//promise对象 
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {//普通值
                    addData(i, array[i])
                }
            }
            resolve(result)
        })
    }

}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
function mP1() {
    return new MyPromise((resolve) => {
        setTimeout(() => resolve('mP1'), 2000)
    })
}
function mP2() {
    return new MyPromise((resolve) => {
        resolve('mP2')
    })
}
MyPromise.all(['a', 'b', mP1(), mP2(), 'c']).then(res => console.log(res))
//["a", "b", empty, "mP2", "c"] 

for循环时,遇到了setTimeout异步,for循环完毕,异步的值还没有返回

class MyPromise {
   //此处省略...
    static all(array) {
        let result = []
        let index = 0//计算数组长度
        return new MyPromise((resolve, reject) => {
            //把方法放进执行器,才能拿到resolve
            function addData(key, value) {
                result[key] = value
                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(value => addData(i, value), reason => reject(reason))
                } else {//普通值
                    addData(i, array[i])
                }
            }
        })
    }

}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
function mP1() {
    return new MyPromise((resolve) => {
        setTimeout(() => resolve('mP1'), 2000)
    })
}
function mP2() {
    return new MyPromise((resolve) => {
        resolve('mP2')
    })
}
MyPromise.all(['a', 'b', mP1(), mP2(), 'c']).then(res => console.log(res))
//(2s后输出)["a", "b", "mP1", "mP2", "c"]

10. Promise.resolve方法的实现

Promise.resolve(10).then(value => console.log(value))//10
function p1() {
    return new Promise((resolve, reject) => resolve('hello'))
}
Promise.resolve(p1()).then(value => console.log(value))//hello

在resolve方法内部先判断给定的参数是不是promise对象,如果是那么就直接返回这个promise对象,如果不是那么我们就创建一个promise对象,把返回值包裹在promise当中,然后再把这个promise对象返回

class MyPromise {
   //此处省略...
    static resolve(value) {
        if (value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }
}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
MyPromise.resolve(100).then(value => console.log(value)) //100
function p1() {
    return new MyPromise((resolve, reject) => resolve('hello'))
}
MyPromise.resolve(p1()).then(value => console.log(value)) //'hello'

11. finally 方法的实现

无论当前这个promise对象最终是成功还是失败,finally方法当中的回调函数始终都会被执行一次。finally方法后面我们可以链式调用then方法拿到当前这个promise对象最终返回的结果,finally不是静态方法

class MyPromise {
   //此处省略...
    finally(callback) {
        return this.then(value => {
            callback()
            return value
        }, reason => {
            callback()
            throw reason
        })
    }
}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
function p1() {
    return new MyPromise((resolve, reject) => {
        resolve('resolve')
        // reject('reject')
    })
}
***  finally 中没有return ***
p1().finally(() => {
    console.log('finally')//finally
    return p2()
}).then(value => {
    console.log(value) //resolve 【resolve('resolve')时】
}, reason => {
    console.log(reason)//reject  【reject('reject')时】
})

***  finally 中有return ***
function p2() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('p2 resolve')
        }, 2000)
    })
}
p1().finally(() => {
    console.log('finally')//finally
    return p2()
}).then(value => {
    console.log(value) //resolve
}, reason => {
    console.log(reason)
})

finally 中有return一个p2时候没有等待2s而是直接返回了 finally;p2 resolve

class MyPromise {
   //此处省略...
    finally(callback) {
        return this.then(value => {
            //不管是promise还是普通值我们都转成promise
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }
}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
function p1() {
    return new MyPromise((resolve, reject) => {
        resolve('resolve')
    })
}
function p2() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('p2 resolve')
        }, 2000)
    })
}
p1().finally(() => {
    console.log('finally')//finally
    return p2()
}).then(value => {
    console.log(value) //(2s后输出) resolve
}, reason => {
    console.log(reason)
})

12. catch 方法的实现

catch用来处理当前这个promise对象当前最终为失败的情况的。当我们调用then方法是是可以不传递失败回调的,当我们没有传递失败回调,那么失败情况就会被catch方法所捕获,从而去执行传入catch方法的回调函数 在catch方法调用then 成功处传undefined 失败传回调函数

class MyPromise {
   //此处省略...
    catch(failCallback) {
        return this.then(undefined, failCallback)
    }
}
function resolvePromise(promise2, x, resolve, reject) {
   //此处省略...
}
function p1() {
    return new MyPromise((resolve, reject) => {
        resolve('resolve')
        // reject('reject')
    })
}
p1().then(value => console.log(value)).catch(reason => console.log(reason))//resolve jeject

13 手写promise整体代码

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }

    }
    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 (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else {
                this.successCallback.push(() => {
                    setTimeout(() => { 
                        try {
                            let x = successCallback(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                });
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCallback(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
            }
        })
        return promise2
    }
    finally(callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }
    catch(failCallback) {
        return this.then(undefined, failCallback)
    }
    static all(array) {
        let result = []
        let index = 0
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value
                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(value => addData(i, value), reason => reject(reason))
                } else {
                    addData(i, array[i])
                }
            }
        })
    }
    static resolve(value) {
        if (value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }

}
function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (x instanceof MyPromise) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}