Skip to content
On this page

Promise 系列

实现一个详细版 Promise

具体实现可以看这一篇文章,手把手一行行写Promise

js
class myPromise {
    // 用static创建静态属性,用来管理状态
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';

    // 构造函数:通过new命令生成对象实例时,自动调用类的构造函数
    constructor(func) { // 给类的构造方法constructor添加一个参数func
        this.PromiseState = myPromise.PENDING; // 指定Promise对象的状态属性 PromiseState,初始值为pending
        this.PromiseResult = null; // 指定Promise对象的结果 PromiseResult
        this.onFulfilledCallbacks = []; // 保存成功回调
        this.onRejectedCallbacks = []; // 保存失败回调
        try {
            /**
             * func()传入resolve和reject,
             * resolve()和reject()方法在外部调用,这里需要用bind修正一下this指向
             * new 对象实例时,自动执行func()
             */
            func(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
            // 生成实例时(执行resolve和reject),如果报错,就把错误信息传入给reject()方法,并且直接执行reject()方法
            this.reject(error)
        }
    }

    resolve(result) { // result为成功态时接收的终值
        // 只能由pending状态 => fulfilled状态 (避免调用多次resolve reject)
        if (this.PromiseState === myPromise.PENDING) {
            this.PromiseState = myPromise.FULFILLED;
            this.PromiseResult = result;
            /**
             * 在执行resolve或者reject的时候,遍历自身的callbacks数组,
             * 看看数组里面有没有then那边 保留 过来的 待执行函数,
             * 然后逐个执行数组里面的函数,执行的时候会传入相应的参数
             */
            this.onFulfilledCallbacks.forEach(callback => {
                callback(result)
            })
        }
    }

    reject(reason) { // reason为拒绝态时接收的终值
        // 只能由pending状态 => rejected状态 (避免调用多次resolve reject)
        if (this.PromiseState === myPromise.PENDING) {
            this.PromiseState = myPromise.REJECTED;
            this.PromiseResult = reason;
            this.onRejectedCallbacks.forEach(callback => {
                callback(reason)
            })
        }
    }

    /**
     * [注册fulfilled状态/rejected状态对应的回调函数] 
     * @param {function} onFulfilled  fulfilled状态时 执行的函数
     * @param {function} onRejected  rejected状态时 执行的函数 
     * @returns {function} newPromsie  返回一个新的promise对象
     */
    then(onFulfilled, onRejected) {
        // 2.2.7规范 then 方法必须返回一个 promise 对象
        let promise2 = new myPromise((resolve, reject) => {
            if (this.PromiseState === myPromise.FULFILLED) {
                /**
                 * 为什么这里要加定时器setTimeout?
                 * 2.2.4规范 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用 注1
                 * 这里的平台代码指的是引擎、环境以及 promise 的实施代码。
                 * 实践中要确保 onFulfilled 和 onRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。
                 * 这个事件队列可以采用“宏任务(macro-task)”机制,比如setTimeout 或者 setImmediate; 也可以采用“微任务(micro-task)”机制来实现, 比如 MutationObserver 或者process.nextTick。
                 */
                setTimeout(() => {
                    try {
                        if (typeof onFulfilled !== 'function') {
                            // 2.2.7.3规范 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
                            resolve(this.PromiseResult);
                        } else {
                            // 2.2.7.1规范 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x),即运行resolvePromise()
                            let x = onFulfilled(this.PromiseResult);
                            resolvePromise(promise2, x, resolve, reject);
                        }
                    } catch (e) {
                        // 2.2.7.2规范 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
                        reject(e); // 捕获前面onFulfilled中抛出的异常
                    }
                });
            } else if (this.PromiseState === myPromise.REJECTED) {
                setTimeout(() => {
                    try {
                        if (typeof onRejected !== 'function') {
                            // 2.2.7.4规范 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因
                            reject(this.PromiseResult);
                        } else {
                            let x = onRejected(this.PromiseResult);
                            resolvePromise(promise2, x, resolve, reject);
                        }
                    } catch (e) {
                        reject(e)
                    }
                });
            } else if (this.PromiseState === myPromise.PENDING) {
                // pending 状态保存的 onFulfilled() 和 onRejected() 回调也要符合 2.2.7.1,2.2.7.2,2.2.7.3 和 2.2.7.4 规范
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            if (typeof onFulfilled !== 'function') {
                                resolve(this.PromiseResult);
                            } else {
                                let x = onFulfilled(this.PromiseResult);
                                resolvePromise(promise2, x, resolve, reject);
                            }
                        } catch (e) {
                            reject(e);
                        }
                    });
                });
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            if (typeof onRejected !== 'function') {
                                reject(this.PromiseResult);
                            } else {
                                let x = onRejected(this.PromiseResult);
                                resolvePromise(promise2, x, resolve, reject);
                            }
                        } catch (e) {
                            reject(e);
                        }
                    });
                });
            }
        })

        return promise2
    }
}

/**
 * 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理
 * @param  {promise} promise2 promise1.then方法返回的新的promise对象
 * @param  {[type]} x         promise1中onFulfilled或onRejected的返回值
 * @param  {[type]} resolve   promise2的resolve方法
 * @param  {[type]} reject    promise2的reject方法
 */
function resolvePromise(promise2, x, resolve, reject) {
    // 2.3.1规范 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
    if (x === promise2) {
        throw new TypeError('Chaining cycle detected for promise');
    }

    if (x instanceof myPromise) {
        /**
         * 2.3.2 如果 x 为 Promise ,则使 promise2 接受 x 的状态
         *       也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
         */
        x.then(y => {
            resolvePromise(promise2, y, resolve, reject)
        }, reject);
    } else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
        // 2.3.3 如果 x 为对象或函数
        try {
            // 2.3.3.1 把 x.then 赋值给 then
            var then = x.then;
        } catch (e) {
            // 2.3.3.2 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
            return reject(e);
        }

        /**
         * 2.3.3.3 
         * 如果 then 是函数,将 x 作为函数的作用域 this 调用之。
         * 传递两个回调函数作为参数,
         * 第一个参数叫做 `resolvePromise` ,第二个参数叫做 `rejectPromise`
         */
        if (typeof then === 'function') {
            // 2.3.3.3.3 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
            let called = false; // 避免多次调用
            try {
                then.call(
                    x,
                    // 2.3.3.3.1 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
                    y => {
                        if (called) return;
                        called = true;
                        resolvePromise(promise2, y, resolve, reject);
                    },
                    // 2.3.3.3.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
                    r => {
                        if (called) return;
                        called = true;
                        reject(r);
                    }
                )
            } catch (e) {
                /**
                 * 2.3.3.3.4 如果调用 then 方法抛出了异常 e
                 * 2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
                 */
                if (called) return;
                called = true;

                // 2.3.3.3.4.2 否则以 e 为据因拒绝 promise
                reject(e);
            }
        } else {
            // 2.3.3.4 如果 then 不是函数,以 x 为参数执行 promise
            resolve(x);
        }
    } else {
        // 2.3.4 如果 x 不为对象或者函数,以 x 为参数执行 promise
        return resolve(x);
    }
}

实现 Promise.resolve

实现 Promise.reject

实现 Promise.finally

实现 Promise.all

实现 Promise.allsettle

实现 Promise.race

实现 Promise.any

使用 Promise 实现每隔 1s 输出 1,2,3

循环打印红黄绿

实现 mergePromise 函数

用 Promise 实现图片异步加载

封装异步的 fetch 使用 async await 方式来使用

实现一个带并发限制的异步调度器 Schduler

实现 cacheRequest,相同资源 Ajax 只发一次请求

手写一个 singlePipe 实现一个任务没有完成,下一个任务不响应

实现 Promise.retry,成功后 resolve,可延迟重试 n 次,超过 n 次数后 reject

Promise 延迟执行

输出结果;如果希望每隔 1s 输出一个结果,应该如何改造?注意不可改动 square 方法

Released under the MIT License.