自己动手实现Promise

2,594 阅读4分钟

自己动手实现Promise

实现了以下方法

  • Promise 的含义
  • 基本用法
  • Promise.prototype.then()
  • Promise.prototype.catch()
  • Promise.prototype.finally()
  • Promise.all()
  • Promise.race()
  • Promise.allSettled()
  • Promise.any()
  • Promise.resolve()
  • Promise.reject()
  • Promise.try()

参考

简介

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

优点

  1. Promise 是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理和更强大。
  2. 链式操作相对于回调函数体验更好。

缺点

  1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  2. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  3. 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

实现基本功能(then、catch)

// 私有变量,三个状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
/**
 * 自己实现Promise
 */
class MyPromise {
    constructor(calllback) {
        // 状态
        this.status = PENDING;
        // 值
        this.value = undefined;
        // 成功回调列表
        this.resolveList = [];
        // 失败回调列表
        this.rejectList = [];

        const resolve = (value) => {
            // 状态仅允许修改一次
            if (this.status !== PENDING){
                return;
            }

            setTimeout(() => {
                this.value = value;
                this.status = FULFILLED;
                for (const func of this.resolveList) {
                    func(this.value);
                }
            }, 0);

        }

        const reject = (reason) => {
            // 状态仅允许修改一次
            if (this.status !== PENDING){
                return;
            }
            setTimeout(() => {
                this.value = reason;
                this.status = REJECTED;
                for (const func of this.rejectList) {
                    func(this.value);
                }
            }, 0);
        }

        try {
            calllback(resolve, reject);
        } catch (err) {
            reject(err);
        }
    }
    // 处理执行结果
    then(onResolve, onReject) {
        let promise = null;
        if (this.status === PENDING) {
            promise = new MyPromise((resolve, reject) => {
                // 解决值穿透
                onResolve = typeof onResolve === 'function' ? onResolve : (value) => value;
                onReject = typeof onReject === 'function' ? onReject : (reason) => {throw reason};
                this.resolveList.push(function(innerValue) {
                    try {
                        const value = onResolve(innerValue);
                        // resolve(value);
                        runThen(promise, value, resolve, reject);
                    } catch (err) {
                        reject(err);
                    }
                });
                this.rejectList.push(function(innerReason) {
                    try {
                        const value = onReject(innerReason);
                        // resolve(value);
                        runThen(promise, value, resolve, reject);
                    } catch (err) {
                        reject(err);
                    }
                });
            });
        } else {
            const innerValue = this.value;
            const isFulfilled = this.status === STATUS.FULFILLED;
            promise = new MyPromise((resolve, reject) => {
                try {
                    const value = isFulfilled ? onResolve(innerValue) : onReject(innerValue); // 失败状态调用 onReject
                    // resolve(value);
                    runThen(promise, value, resolve, reject);
                } catch (error) {
                    reject(error)
                }
            })
        }
        return promise;
        // 运行promise,处理then返回新promise和循环引用问题
        function runThen(promise, value, resolve, reject) {
            if (promise === value) {
                reject(new TypeError('Chaining cycle detected for promise'));
                return;
            }
            if (value instanceof MyPromise) {
                value.then((val) => runThen(promise, val, resolve, reject), (reason) => reject(reason));
            } else {
                resolve(value);
            }
        }
    }
    // 处理失败
    catch(onReject) {
        return this.then(null, onReject);
    }
}

其他方法实现(finally、resolve、reject、all、race、any、allSettled、try)

// 私有变量,三个状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
/**
 * 自己实现Promise
 */
class MyPromise {
    constructor(calllback) {
        // 状态
        this.status = PENDING;
        // 值
        this.value = undefined;
        // 成功回调列表
        this.resolveList = [];
        // 失败回调列表
        this.rejectList = [];

        const resolve = (value) => {
            // 状态仅允许修改一次
            if (this.status !== PENDING){
                return;
            }

            setTimeout(() => {
                this.value = value;
                this.status = FULFILLED;
                for (const func of this.resolveList) {
                    func(this.value);
                }
            }, 0);

        }

        const reject = (reason) => {
            // 状态仅允许修改一次
            if (this.status !== PENDING){
                return;
            }
            setTimeout(() => {
                this.value = reason;
                this.status = REJECTED;
                for (const func of this.rejectList) {
                    func(this.value);
                }
            }, 0);
        }

        try {
            calllback(resolve, reject);
        } catch (err) {
            reject(err);
        }
    }
    // 处理执行结果
    then(onResolve, onReject) {
        let promise = null;
        if (this.status === PENDING) {
            promise = new MyPromise((resolve, reject) => {
                // 解决值穿透
                onResolve = typeof onResolve === 'function' ? onResolve : (value) => value;
                onReject = typeof onReject === 'function' ? onReject : (reason) => {throw reason};
                this.resolveList.push(function(innerValue) {
                    try {
                        const value = onResolve(innerValue);
                        // resolve(value);
                        runThen(promise, value, resolve, reject);
                    } catch (err) {
                        reject(err);
                    }
                });
                this.rejectList.push(function(innerReason) {
                    try {
                        const value = onReject(innerReason);
                        // resolve(value);
                        runThen(promise, value, resolve, reject);
                    } catch (err) {
                        reject(err);
                    }
                });
            });
        } else {
            const innerValue = this.value;
            const isFulfilled = this.status === STATUS.FULFILLED;
            promise = new MyPromise((resolve, reject) => {
                try {
                    const value = isFulfilled ? onResolve(innerValue) : onReject(innerValue); // 失败状态调用 onReject
                    // resolve(value);
                    runThen(promise, value, resolve, reject);
                } catch (error) {
                    reject(error)
                }
            })
        }
        return promise;
        // 运行promise,处理then返回新promise和循环引用问题
        function runThen(promise, value, resolve, reject) {
            if (promise === value) {
                reject(new TypeError('Chaining cycle detected for promise'));
                return;
            }
            if (value instanceof MyPromise) {
                value.then((val) => runThen(promise, val, resolve, reject), (reason) => reject(reason));
            } else {
                resolve(value);
            }
        }
    }
    // 处理失败
    catch(onReject) {
        return this.then(null, onReject);
    }
    // 无论成功失败都执行
    finally(callback) {
        return this.then(callback, callback);
    }
    // 直接返回成功
    static resolve(value) {
        return new MyPromise((resolve, reject) => resolve(value));
    }
    // 直接返回失败
    static reject(reason) {
        return new MyPromise((resolve, reject) => reject(reason));
    }
    // 所有都执行完毕
    static all(promiseList) {
        let count = 0;
        const length = promiseList.length;
        const valueList = [];
        return new MyPromise((resolve, reject) => {
            promiseList.forEach((promise, index) => {
                promise.then((res) => {
                    valueList[index] = res;
                    count++;
                    if (count >= length) {
                        resolve(valueList);
                    }
                }).catch((err) => {
                    reject(err);
                });
            });
        });
    }
    // 第一个执行完毕
    static race(promiseList) {
        return new MyPromise((resolve, reject) => {
            promiseList.forEach((promise, index) => {
                promise.then((res) => {
                    resolve(res);
                }).catch((err) => {
                    reject(err);
                });
            });
        });
    }
    // 任何一个执行成功则返回成功,否则失败
    static any(promiseList) {
        let count = 0;
        const length = promiseList.length;
        const valueList = [];
        return new MyPromise((resolve, reject) => {
            promiseList.forEach((promise, index) => {
                promise.then((res) => {
                    resolve(res);
                }).catch((err) => {
                    valueList[index] = err;
                    count++;
                    if (count >= length) {
                        reject(valueList);
                    }
                });
            });
        });
    }
    // 所有都执行完,无论成功失败都返回成功
    static allSettled(promiseList) {
        let count = 0;
        const length = promiseList.length;
        const valueList = [];
        return new MyPromise((resolve, reject) => {
            promiseList.forEach((promise, index) => {
                promise.then((res) => {
                    valueList[index] = res;
                    count++;
                    if (count >= length) {
                        resolve(valueList);
                    }
                }).catch((err) => {
                    valueList[index] = err;
                    count++;
                    if (count >= length) {
                        resolve(valueList);
                    }
                });
            });
        });
    }
    // 执行同步或者异步函数
    static try(func) {
        return new MyPromise((resolve, reject) => {
            const result = func();
            resolve(result);
        });
    }
}