Promise规范解读及简易实现

864 阅读31分钟

Promise详解

为什么需要Promise

JavaScript是一门单线程语言,所以早期我们解决异步的场景时,大部分情况都是通过回调函数来处理。 例如,在浏览器中发送ajax请求,就是常见的一个异步场景,发送请求后,一段时间服务端响应之后我们才能拿到结果。如果我们希望在异步结束之后执行某个操作,就只能通过回调函数这样的方式进行操作。

const dynamicFunc = function (cb) {
    setTimeout(() => {
        cb()
    }, 1000)
}
dynamicFunc(function () {
    console.log(123)
})

上面这个例子中dynamicFunc就是一个异步函数,里面执行的setTimeout会在1s之后将cb函数放入事件队列,待主线程代码执行完后调用cb函数。按照上面的调用方式,最终延迟1s后会打印123这个结果。 同样的,如果后续还有内容需要在异步函数结束时输出的话,就需要多个异步函数进行嵌套,非常不利于后续的维护。

Promise是如何使用的

在支持ES6的高级浏览器环境中,我们通过new Promise()即可创建一个promise实例。 这个构造函数接收一个函数,分别接收两个参数:resolve和reject,代表着改变当前实例的状态为已完成或者已拒绝

function promise1() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('1s后输出')
            resolve();
        }, 1000)
    })
}

function promise2() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('2s后输出')
            resolve();
        }, 2000)
    })
}

上面两个promise实例,串联起来即可写为: promise1().then(() => promise2()) 也可以简写为: promise1().then(promise2)

浏览器中执行之后,即可看到,1s之后出现1s后输出字样,在经过2s出现2s后输出字样。在这个例子中我们能看到:当前promise如果状态变为已完成(执行了resolve方法),那么就会去执行then方法中的下一个promise函数。

同样的,如果promise变为已拒绝状态(执行了reject方法),那么就会进入后续的异常处理函数中。

function promise3() {
    return new Promise(function (resolve, reject) {
        var random = Math.random() * 10;
        setTimeout(function () {
            if (random >= 5) {
                resolve(random);
            } else {
                reject(random);
            }
        }, 1000);
    });
}

var onResolve = function (val) {
    console.log('已完成:输出的数字是:', val);
};
var onReject = function (val) {
    console.log('已拒绝:输出的数字是:', val);
}

promise3().then(onResolve, onReject);

// 可以通过catch方法拦截状态变为已拒绝的promise
promise3().catch(onReject).then(onResolve);

// 也可以通过try catch 拦截状态变为已拒绝的promise
try {
    promise3().then(onResolve);
} catch (e) {
    onReject(e);
}

这个例子使用了三种方式拦截最终变为已拒绝状态的promise,分别使用then的第二个参数,使用.catch方法捕获前方promise抛出的异常,使用try catch拦截代码块中promise抛出的异常

同时,我们还发现,在改变promise状态时调用resolve和reject函数的时候,也可以给下一步then中执行的函数传递参数。这个例子中把随机生成的数字传给了resolve和reject函数,我们也就能在then中执行函数的时候拿到这个值。

总结:

  1. promise会有三种状态,进行中 已完成 已拒绝,进行中状态可以更改为已完成或已拒绝,已经更改过状态后无法继续更改(例如不能从已完成改为已拒绝)
  2. ES6中的Promise构造函数,需要传入一个函数,接收两个函数参数,执行第一个参数之后就会改变当前promise为已完成状态,执行第二个参数之后就会变为已拒绝状态
  3. 通过.then方法,即可在上一个promise变为已完成状态时继续执行下一个函数或promise。同时,通过resolve或reject时传递参数,即可给下一个函数或promise传入初始值
  4. 已拒绝的promise后续可以通过.catch方法或者.then方法的第二个参数或者try catch进行捕获

promise规范解读

任何符合promise规范的对象或函数都可以成为promise,promises/A+规范地址:promisesaplus.com/

上面我们熟悉了整体promise的用法,知道了如何去创建一个promise,如何使用它,也熟悉了如何去改造回调函数到promise。本小节我们详细过一遍promises/A+规范,从规范层面明白Promise使用过程中的细节。

术语

  • Promise:promise是一个拥有then方法的对象或函数,其行为符合本规范
  • 具有then方法(thenable):是一个定义了then方法的对象或函数
  • 值(value):指任何JavaScript的合法值(包括undefined,thenable和promise)
  • 异常(exception):是使用throw语句抛出的一个值
  • 原因(reason):表示一个promise的拒绝原因

要求

promise的状态

一个Promise的当前状态必须为一下三种状态中的一种:等待态(Pending)、已完成(Fulfilled)、已拒绝(Rejected)

  • 处于等待态时,promise需满足一下条件:可以变为已完成已拒绝
  • 处于已完成时,promise需满足一下条件:1.不能改变为其他任何状态 2.必须拥有一个不可变的值
  • 处于已拒绝时,promise需满足以下条件:1.不能改变为其他任何状态 2.必须拥有一个不可变的原因

必须有一个then方法

一个promise必须提供一个then方法以访问其当前值和原因。 promise的then方法接收两个参数:promise.then(onFulfilled, onRejected)他们都是可选参数,同时他们都是函数,如果onFulfilledonRejected不是函数,则需要忽略他们。

  • 如果onFulfilled是一个函数
    • promise执行结束后其必须被调用,其第一个参数为promise的结果
    • promise执行结束前其不可被调用
    • 其调用次数不可超过一次
  • 如果onRejected是一个函数
    • promise被拒绝执行后其必须被调用,其第一个参数为promise的原因
    • promise被拒绝执行前其不可被调用
    • 其调用次数不可超过一次
  • 在执行上下文堆栈仅包含平台代码之前,不得调用onFulfilledonRejected
  • onFulfilledonRejected必须被作为普通函数调用(即非实例化调用,这样函数内部this非严格模式下指向window)
  • then方法可以被同一个promise调用多次
    • promise成功执行时,所有onFulfilled需按照其注册顺序依次回调
    • promise被拒绝执行时,所有的onRejected需按照其注册顺序依次回调
  • then方法必须返回一个promise对象promise2 = promise1.then(onFulfilled, onRejected)
    • 只要onFulfilledonRejected返回一个值x,promise2都会进入onFulfilled状态
    • 只要onFulfilledonRejected抛出一个异常e,则promise2必须拒绝执行,并返回原因e
  • 如果onFulfilled不是函数且promise1状态变为已完成,promise2必须成功执行并返回相同的值
  • 如果onRejected不是函数且promise1状态变为已拒绝,promise2必须执行拒绝回调并返回相同的原因
var promise1 = new Promise((resolve, reject) => { reject(); });
promise1
    .then(null, function () {
        return 123;
    })
    .then(null, null)
    .then(null, null)
    .then(
        () => {
            console.log('promise2已完成');
        },
        () => {
            console.log('promise2已拒绝');
        });

promise的解决过程

**promise解决过程是一个抽象的操作,其需输入一个promise和一个值,我们表示为[[Resolve]](promise, x)(这句话的意思就是把promise resolve,同时传入x作为值)

promise.then(x => {
    console.log('会执行这个函数,同时传入x变量的值: ', x)
})

如果xthen方法且看上去像一个Promise,解决程序即尝试使promise接受x的状态;否则其用x的值来执行promise

  • 如果promisex指向同一个对象,以TypeError为原因拒绝执行promise
  • 如果xpromise
    • 如果x处于等待态,promise需保持为等待态直至x被执行或拒绝
    • 如果x处于执行态,用相同的值执行promise
    • 如果x处于拒绝态,用相同的原因拒绝promise
var promise1 = function () {
    return new Promise(function (resolve) {
        setTimeout(function () {
            console.log(1);
            resolve();
        }, 1000)
    });
}
var promise2 = function () {
    return new Promise(function (resolve) {
        setTimeout(function () {
            console.log(2);
            resolve();
        }, 2000);
    });
}
promise1()
    .then(function () {
        return promise2(); // 此处返回一个promise实例
    })
    .then(function () { console.log('已完成') }, function () { console.log('已拒绝') });
  • 如果x为Object或function(不常见)
    • 首先尝试执行x.then
    • 如果取x.then的值时抛出错误e,则以e为原因拒绝promise
    • 如果then是函数,将x作为函数的作用域this调用。传递两个回调函数作为参数,第一个参数叫做resolvePromise,第二个叫做rejectPromise
      • 如果resolvePromise以值y为参数被调用,则运行`[[Resolve]](promise, y)
      • 如果rejectPromise以据因r为参数被调用,则以据因r拒绝promise
      • 如果resolvePromiserejectPromise均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略其他的调用
      • 如果调用then方法抛出了异常e
        • 如果resolvePromiserejectPromise已被调用,则忽略
        • 否则以e为据因拒绝promise
    • 如果then不为函数,以x为参数将promise变为已完成状态
  • 如果x不为对象或者函数,以x为参数将promise变为已完成状态**(重要且常见)**

Promise构造函数上的静态方法

Promise.resolve

返回一个promise实例,并将它的状态设置为已完成,同时将它的结果作为传入promise实例的值

var promise = Promise.resolve(123);
promise
    .then(function (val) {
        console.log('???', val);
    });
// 已完成 123

同样的,Promise.resolve的参数也可以处理对象、函数等内容,处理方式和上面规范中介绍的相同。

Promise.reject

返回一个promise实例,并将它的状态设置为已拒绝,同时也将它的结果作为原因传入onRejected函数

var promise = Promise.reject(123);
promise
    .then(null, function (val) {
        console.log('已拒绝', val);
    });
// 已拒绝 123

Promise.all

返回一个promise实例,接收一个数组,里面含有多个promise实例,当所有promise实例都成为已完成状态时,进入已完成状态,否则进入已拒绝状态。

var promise1 = function () {
    return new Promise(function (resolve) {
        setTimeout(function () {
            console.log(1);
            resolve();
        }, 1000)
    });
}
var promise2 = function () {
    return new Promise(function (resolve) {
        setTimeout(function () {
            console.log(2);
            resolve();
        }, 2000);
    });
}

Promise.all([promise1(), promise2()])
    .then(function () {
        console.log('全部promise均已完成');
    });

注意,此时多个promise是同时进行的,也就是在上面这个例子中,等待1s打印1之后,在等待1s就会打印打印2和'全部promise均已完成'。

Promise.race

返回一个promise实例,接收一个数组,里面含有多个promise实例,当有一个promise实例状态改变时,就进入该状态且不可改变。这里所有的promise实例为竞争关系,只选择第一个进入改变状态的promise的值。

var promise1 = function () {
    return new Promise(function (resolve) {
        setTimeout(function () {
            console.log(1);
            resolve(1);
        }, 1000)
    });
}
var promise2 = function () {
    return new Promise(function (resolve) {
        setTimeout(function () {
            console.log(2);
            resolve(2);
        }, 2000);
    });
}
Promise.race([promise1(), promise2()])
    .then(function (val) {
        console.log('有一个promise状态已经改变:', val);
    });

实现一个简易的promise

Promise类核心逻辑实现

  1. Promise就是一个类,在对这个类进行实例化的时候要传递一个执行器函数,并且执行器立即执行
  2. Promise中对应三种状态:成功(fulfilled)失败(rejected)等待(pending)
  3. 执行resolve方法的时候状态由pending变为fulfilled,执行reject方法的时候状态由pending变为rejected,而且状态一经确定便不可再更改
  4. then方法定义在原型对象中,接收两个参数分别为成功的回调函数和失败的回调函数
  5. then方法作用为判断状态,状态成功则调用成功的回调函数(参数表示成功传递的值),状态失败则调用失败的回调函数(参数表示失败的原因)
// 定义常量的目的:1.表示promise的不同状态 2.可以让编辑器有代码提示(哈哈)
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENDING // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
    }
    then(successCb, failCb) {
        // 判断状态
        if (this.status === FULFILLED) { // 同步调用
            successCb(this.successData) // 调用成功回调,把值返回
        } else if (this.status === REJECTED) { // 同步调用
            failCb(this.failReason) // 调用失败回调,把原因返回
        }
    }
}
const promise = new MyPromise((resolve, reject) => {
    resolve('success')
    // reject('fail')
});

promise.then(val => {
    console.log(val)
}, reason => {
    console.log(reason)
})

Promise中加入异步逻辑

上面代码是没有经过异步处理的,如果有异步逻辑则会出现问题

const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENDING // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = undefined // 存储成功的回调函数
    failCallback = undefined // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        this.successCallback && this.successCallback(this.successData) // 异步逻辑下调用成功的回调
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        this.failCallback && this.failCallback(this.failReason) // 异步逻辑下调用失败的回调
    }
    then(successCb, failCb) {
        // 判断状态
        if (this.status === FULFILLED) { // 同步调用
            successCb(this.successData) // 调用成功回调,把值返回
        } else if (this.status === REJECTED) { // 同步调用
            failCb(this.failReason) // 调用失败回调,把原因返回
        } else { // 异步调用
            this.successCallback = successCb // 存储成功的回调
            this.failCallback = failCb // 存储失败的回调
        }
    }
}
const promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        // resolve('success')
        reject('fail')
    }, 1500)
});

promise.then(val => {
    console.log(val)
}, reason => {
    console.log(reason)
})

实现Promise then方法被多次调用

  1. Promise的then方法是可以被多次调用的。
  2. 下面示例有三个then的回调,如果是同步回调,那么直接返回当前的值就可以。
  3. 如果是异步回调,那么需要用不同的值保存成功失败的回调,因为互不相同。
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENDING // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while(this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()(this.successData)
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while(this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()(this.failReason)
        }
    }
    then(successCb, failCb) {
        // 判断状态
        if (this.status === FULFILLED) { // 同步调用
            successCb(this.successData) // 调用成功回调,把值返回
        } else if (this.status === REJECTED) { // 同步调用
            failCb(this.failReason) // 调用失败回调,把原因返回
        } else { // 异步调用
            this.successCallback.push(successCb) // 存储成功的回调
            this.failCallback.push(failCb) // 存储失败的回调
        }
    }
}

测试示例:

const promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
        // reject('fail')
    }, 1500)
});

promise.then(val => {
    console.log(val, 11)
}, reason => {
    console.log(reason, 11)
})

promise.then(val => {
    console.log(val, 22)
}, reason => {
    console.log(reason, 22)
})

promise.then(val => {
    console.log(val, 33)
}, reason => {
    console.log(reason, 33)
})

实现Promise then方法的链式调用

  1. Promise的then方法是可以被链式调用,后面then方法的回调函数参数值是上一个then方法回调函数的返回值。
  2. 其中then方法回调函数参数传递包含两种情况:1.参数为普通值 2.参数为另一个promise对象
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENDING // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()(this.successData)
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()(this.failReason)
        }
    }
    then(successCb, failCb) {
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                const s = successCb(this.successData) // 调用成功回调,把值返回
                // 判断 p 是普通值还是promise对象
                // 如果是普通值则直接调用resolve
                // 如果是promise对象,则根据promise对象返回结果决定调用resolve还是reject
                parsePromiseStatus(s, resolve, reject)
            } else if (this.status === REJECTED) { // 同步调用
                const f = failCb(this.failReason) // 调用失败回调,把原因返回
                parsePromiseStatus(f, resolve, reject)
            } else { // 异步调用
                this.successCallback.push(successCb) // 存储成功的回调
                this.failCallback.push(failCb) // 存储失败的回调
            }
        })
        return promise
    }
}
function parsePromiseStatus(p, resolve, reject) {
    if (p instanceof MyPromise) {
        p.then(resolve, reject)
    } else {
        resolve(p)
    }
}

测试示例:

const promise = new MyPromise((resolve, reject) => {
    resolve('success') // 目前这里只处理了同步的问题
});

function anther(n) {
    return new MyPromise((resolve, reject) => {
        resolve('anther' + (n || ''))
    })
}

const p = promise.then(val => {
    console.log('val: ', val)
    // return '2222'
    return anther()
}, reason => {
    console.log('reason', reason)
    return anther(2)
}).then(val => {
    console.log('val2: ', val)
}, reason => {
    console.log('reason2: ', reason)
})

then方法链式调用识别返回promise对象自身

const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENDING // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()(this.successData)
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()(this.failReason)
        }
    }
    then(successCb, failCb) {
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => { // 使用setTimeout的原因:不使用的话此时方法没执行完毕,不能得到返回值promise
                    const p = successCb(this.successData) // 调用成功回调,把值返回
                    // 判断 p 是普通值还是promise对象
                    // 如果是普通值则直接调用resolve
                    // 如果是promise对象,则根据promise对象返回结果决定调用resolve还是reject
                    parsePromiseStatus(promise, p, resolve, reject)
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                failCb(this.failReason) // 调用失败回调,把原因返回
            } else { // 异步调用
                this.successCallback.push(successCb) // 存储成功的回调
                this.failCallback.push(failCb) // 存储失败的回调
            }
        })
        return promise
    }
}

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

测试示例:

const promise = new MyPromise((resolve, reject) => {
    resolve('success')
});

const p = promise.then(val => {
    console.log(val, 'resolved')
    return p
}, reason => {
    console.log(reason, 'rejected')
})

p.then(val => {
    console.log(val, 22)
}, reason => {
    console.log(reason.message)
})

错误捕获

分为两种:1.执行器的错误捕获 2.then执行的时候错误捕获

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 // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()(this.successData)
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()(this.failReason)
        }
    }
    then(successCb, failCb) {
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = successCb(this.successData)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = failCb(this.failReason)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else { // 异步调用
                this.successCallback.push(successCb) // 存储成功的回调
                this.failCallback.push(failCb) // 存储失败的回调
            }
        })
        return promise
    }
}

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

测试示例:

const promise = new MyPromise((resolve, reject) => {
    reject('success')
    // throw new Error('executor error')
});

promise.then(val => {
    console.log(val, 'resolved')
}, reason => {
    console.log(reason, 'rejected')
    throw new Error('then method error')
}).then(val => {
    console.log(val, 'then2')
}, reason => {
    console.log(reason.message)
})

异步状态下链式调用——promise异步调用resolve或者reject

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 // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()()
        }
    }
    then(successCb, failCb) {
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = successCb(this.successData)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = failCb(this.failReason)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else { // 异步调用
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = successCb(this.successData)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储成功的回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = failCb(this.failReason)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储失败的回调
            }
        })
        return promise
    }
}

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

测试示例:

const promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    }, 1000)
});

promise.then(val => {
    console.log(val, 'resolved')
    return 'xxx'
}, reason => {
    console.log(reason, 'rejected')
}).then(val => {
    console.log(val, 'then2')
}, reason => {
    console.log(reason.message)
})

将then方法的参数变为可选参数

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 // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()()
        }
    }
    then(successCb, failCb) {
        successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
        failCb = failCb || (reason => { throw reason })
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = successCb(this.successData)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = failCb(this.failReason)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else { // 异步调用
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = successCb(this.successData)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储成功的回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = failCb(this.failReason)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储失败的回调
            }
        })
        return promise
    }
}

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

测试示例:

const promise = new MyPromise((resolve, reject) => {
        // resolve('success')
        reject('fail')
});

promise.then().then().then(val => {
    console.log('resolved: ', val)
}, reason => {
    console.log('rejected: ', reason)
})

Promise.all方法的实现

  1. all方法接收一个数组,数组的每个元素可以是普通值也可以是promise对象
  2. 数组中元素的顺序就是得到结果的顺序
  3. 如果数组中所有值是成功的,那么then里面函数就作为成功回调,如果有一个值是失败的,那么then里面函数就作为失败回调
  4. all方法由类直接调用,那么all肯定是类的静态方法
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 // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()()
        }
    }
    then(successCb, failCb) {
        successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
        failCb = failCb || (reason => { throw reason })
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = successCb(this.successData)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = failCb(this.failReason)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else { // 异步调用
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = successCb(this.successData)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储成功的回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = failCb(this.failReason)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储失败的回调
            }
        })
        return promise
    }
    static all(arr) {
        const result = []
        let count = 0
        return new MyPromise((resolve, reject) => {
            function addArrayEle(key, value) {
                result[key] = value
                count++
                // 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
                if (count === arr.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => addArrayEle(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addArrayEle(i, current)
                }
            }
        })
    }
}

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

测试示例:

function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('p1')
        }, 2000)
    })
}

function p2() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('p2')
        }, 1000)
    })
}

MyPromise.all(['a', 'b', p1(), 'c', p2()]).then(val => {
    console.log('val: ', val) // ["a", "b", "p1", "c", "p2"]
})

Promise.race方法的实现

  1. race方法接收一个数组,每个元素可以是普通值也可以是promise对象
  2. 当存在普通值时,立即返回该值;当所有元素均为promise对象时,如果有一个实例状态改变,就进入该状态且不可改变
  3. 这里所有的promise实例为竞争关系,只选择第一个进入改变状态的promise值或者普通值
  4. race方法由类直接调用,那么all肯定是类的静态方法
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 // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()()
        }
    }
    then(successCb, failCb) {
        successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
        failCb = failCb || (reason => { throw reason })
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = successCb(this.successData)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = failCb(this.failReason)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else { // 异步调用
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = successCb(this.successData)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储成功的回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = failCb(this.failReason)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储失败的回调
            }
        })
        return promise
    }
    static all(arr) {
        const result = []
        let count = 0
        return new MyPromise((resolve, reject) => {
            function addArrayEle(key, value) {
                result[key] = value
                count++
                // 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
                if (count === arr.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => addArrayEle(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addArrayEle(i, current)
                }
            }
        })
    }
    static race(arr) {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => resolve(value), reason => reject(reason))
                } else {
                    resolve(current)
                }
            }
        })
    }
}

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

测试示例:

function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('p1')
        }, 3000)
    })
}

function p2() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            reject('p2')
        }, 1000)
    })
}

MyPromise.race(['b', p1(), 'a', p2()]).then(val => {
    console.log('val: ', val); // val: b
}, reason => {
    console.log('reason: ', reason)
})

Promise.resolve方法的实现

  1. 如果参数是一个promise对象,则直接返回;如果是一个值,则生成一个promise对象把值返回
  2. resolve是类的一个静态方法
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 // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()()
        }
    }
    then(successCb, failCb) {
        successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
        failCb = failCb || (reason => { throw reason })
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = successCb(this.successData)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = failCb(this.failReason)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else { // 异步调用
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = successCb(this.successData)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储成功的回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = failCb(this.failReason)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储失败的回调
            }
        })
        return promise
    }
    static all(arr) {
        const result = []
        let count = 0
        return new MyPromise((resolve, reject) => {
            function addArrayEle(key, value) {
                result[key] = value
                count++
                // 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
                if (count === arr.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => addArrayEle(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addArrayEle(i, current)
                }
            }
        })
    }
    static race(arr) {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => resolve(value), reason => reject(reason))
                } else {
                    resolve(current)
                }
            }
        })
    }
    static resolve(value) {
        if(value instanceof MyPromise) {
            return value
        }
        return new MyPromise(resolve => resolve(value))
    }
}

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

测试示例:

function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('p1')
        }, 2000)
    })
}

MyPromise.resolve(2000).then(val => {
    console.log('val: ', val) // 2000
})

MyPromise.resolve(p1()).then(val => {
    console.log('val: ', val) // 'p1'
})

Promise.reject方法的实现

  1. 如果参数是一个promise对象,则直接返回;如果是一个值,则生成一个promise对象把值返回
  2. resolve是类的一个静态方法
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 // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()()
        }
    }
    then(successCb, failCb) {
        successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
        failCb = failCb || (reason => { throw reason })
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = successCb(this.successData)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = failCb(this.failReason)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else { // 异步调用
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = successCb(this.successData)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储成功的回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = failCb(this.failReason)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储失败的回调
            }
        })
        return promise
    }
    static all(arr) {
        const result = []
        let count = 0
        return new MyPromise((resolve, reject) => {
            function addArrayEle(key, value) {
                result[key] = value
                count++
                // 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
                if (count === arr.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => addArrayEle(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addArrayEle(i, current)
                }
            }
        })
    }
    static race(arr) {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => resolve(value), reason => reject(reason))
                } else {
                    resolve(current)
                }
            }
        })
    }
    static resolve(value) {
        if (value instanceof MyPromise) {
            return value
        }
        return new MyPromise(resolve => resolve(value))
    }
    static reject(reason) {
        return new MyPromise((resolve, reject) => reject(reason))
    }
}

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

测试示例:

MyPromise.reject(1234).then(null, val => {
    console.log('val: ', val) // val: 123
})

finally方法的实现

  1. 在原型对象上使用,所以不是静态方法
  2. 无论当前状态是成功还是失败,finally都会执行
  3. 可以在finally方法之后调用then方法得到结果
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 // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()()
        }
    }
    then(successCb, failCb) {
        successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
        failCb = failCb || (reason => { throw reason })
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = successCb(this.successData)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = failCb(this.failReason)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else { // 异步调用
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = successCb(this.successData)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储成功的回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = failCb(this.failReason)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储失败的回调
            }
        })
        return promise
    }
    finally(callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }
    static all(arr) {
        const result = []
        let count = 0
        return new MyPromise((resolve, reject) => {
            function addArrayEle(key, value) {
                result[key] = value
                count++
                // 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
                if (count === arr.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => addArrayEle(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addArrayEle(i, current)
                }
            }
        })
    }
    static race(arr) {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => resolve(value), reason => reject(reason))
                } else {
                    resolve(current)
                }
            }
        })
    }
    static resolve(value) {
        if (value instanceof MyPromise) {
            return value
        }
        return new MyPromise(resolve => resolve(value))
    }
    static reject(reason) {
        return new MyPromise((resolve, reject) => reject(reason))
    }
}

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

测试示例:

function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('p1')
        }, 2000)
    })
}

function p2() {
    return new MyPromise((resolve, reject) => {
        reject('p1')
    })
}

p2().finally(() => {
    console.log('finally')
    return p1()
}).then(val => {
    console.log('resolve: ', val)
}, reason => {
    console.log('reject: ', reason)
})

catch方法的实现

  1. 在原型对象上使用,所以不是静态方法
  2. 直接调用then方法,第一个参数传递undefined,第二个参数传递reason
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 // 实例属性用来表示promise状态
    successData = undefined // 存储成功后resolve传递的参数
    failReason = undefined // 存储失败后reject传递的参数
    successCallback = [] // 存储成功的回调函数
    failCallback = [] // 存储失败的回调函数
    resolve = (val) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = FULFILLED // 将状态改为成功
        this.successData = val // 存储成功之后的值
        while (this.successCallback.length) { // 异步逻辑下调用成功的回调
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
        this.status = REJECTED // 将状态改为失败
        this.failReason = reason // 存储失败之后的值
        while (this.failCallback.length) { // 异步逻辑下调用失败的回调
            this.failCallback.shift()()
        }
    }
    then(successCb, failCb) {
        successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
        failCb = failCb || (reason => { throw reason })
        const promise = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status === FULFILLED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = successCb(this.successData)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) { // 同步调用
                setTimeout(() => {
                    try {
                        const p = failCb(this.failReason)
                        parsePromiseStatus(promise, p, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else { // 异步调用
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = successCb(this.successData)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储成功的回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const p = failCb(this.failReason)
                            parsePromiseStatus(promise, p, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                }) // 存储失败的回调
            }
        })
        return promise
    }
    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(arr) {
        const result = []
        let count = 0
        return new MyPromise((resolve, reject) => {
            function addArrayEle(key, value) {
                result[key] = value
                count++
                // 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
                if (count === arr.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => addArrayEle(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addArrayEle(i, current)
                }
            }
        })
    }
    static race(arr) {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i]
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => resolve(value), reason => reject(reason))
                } else {
                    resolve(current)
                }
            }
        })
    }
    static resolve(value) {
        if (value instanceof MyPromise) {
            return value
        }
        return new MyPromise(resolve => resolve(value))
    }
    static reject(reason) {
        return new MyPromise((resolve, reject) => reject(reason))
    }
}

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

测试示例:

function p2() {
    return new MyPromise((resolve, reject) => {
        reject('p2 failed')
    })
}

p2().then(val => {
    console.log('resolve: ', val)
}).catch(reason => {
    console.log('fail: ', reason) // fail:  p2 failed
})