手写满足PromiseA+规范源码(上)

511 阅读2分钟

Promise简介

Promise可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数(即回调地狱)。

Promise对象有构造函数executor,其含有两个参数resolve和reject,resolve来表示承诺实现,reject表示承诺拒绝。

promiseA+规范英文链接

promiseA+规范中文链接

Promise手写类测试工具

promises-aplus-tests 来测试你的promise是否符合promiseA+规范
使用方式
    安装:npm i promises-aplus-tests -g
    修改package.json:"test": "promises-aplus-tests MyPromise.js"  
// MyPromise.js中新增代码
MyPromise.defer = MyPromise.deferred = function () {
    let dfd = {};
    dfd.promise = new MyPromise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
}
try {
    module.exports = MyPromise;
} catch (err) { }

promise基本功能实现

下述示例代码中,定义了一个MyPromise类,定义三个常量状态(pending-未执行完成,fulfilled-承诺实现,rejected-承诺失败),构造函数中定义了promise的状态,成功值,失败值和成功的回调方法resolve、失败的回调reject方法,在MyPromise类的原型上定义了then方法。

该代码目前存在的缺陷,接下来我会从这两大方面进行完善示例代码:
    1.在MyPromise中无法执行异步函数 
    2.无法进行链式和嵌套调用(会在下一篇文章中进行解释)
const promise = new MyPromise((resolve, reject) => {
     resolve("promise fulfilled");
});

promise.then((value) => {
    console.log("fulfilled:", value);
}, (reason) => {
    console.log("rejected:", reason);
})

const FULFILLED_STATUS = "fulfilled";
const REJECTED_STATUS = "rejected";
const PENDING_STATUS = "pending";

class MyPromise {
    constructor(executor) {
        this.status = PENDING_STATUS;
        this.value = undefined;
        this.reason = undefined;

        const resolve = (value) => {
            if (this.status === PENDING_STATUS) {
                this.status = FULFILLED_STATUS;
                this.value = value;
            }
        }

        const reject = (reason) => {
            if (this.status === PENDING_STATUS) {
                this.status = REJECTED_STATUS;
                this.reason = reason;
            }
        }

        try {
            executor(resolve, reject);
        } catch (e) {
            reject(e);
        }
    }

    then(onFulfilled, onRejected) {
        if (this.status === FULFILLED_STATUS) {
            onFulfilled(this.value);
        } else if (this.status === REJECTED_STATUS) {
            onRejected(this.reason);
        }
    }
}

promise功能完善

MyPromise中无法执行异步函数

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

promise.then((value) => {
    console.log("fulfilled:", value);
}, (reason) => {
    console.log("rejected:", reason);
})

问题产生原因:setTimeout为异步函数,属于宏任务,延后执行。先调用promise.then方法,此时并未执行resolve,故promise的status状态仍为pending,在上述代码中并未对pengding的状态进行处理。

解决思路:依赖收集和派发更新。在then方法中对pending状态进行函数依赖收集,在resolve或reject方法被调用时进行函数调用。

const FULFILLED_STATUS = "fulfilled";
const REJECTED_STATUS = "rejected";
const PENDING_STATUS = "pending";

class MyPromise {
    constructor(executor) {
        this.status = PENDING_STATUS;
        this.value = undefined;
        this.reason = undefined;
        this.onFulfillCallbacks = [];
        this.onRejectCallbacks = [];

        const resolve = (value) => {
            if (this.status === PENDING_STATUS) {
                this.status = FULFILLED_STATUS;
                this.value = value;
                this.onFulfillCallbacks.forEach(fn => fn());
            }
        }

        const reject = (reason) => {
            if (this.status === PENDING_STATUS) {
                this.status = REJECTED_STATUS;
                this.reason = reason;
                this.onRejectCallbacks.forEach(fn => fn());
            }
        }

        try {
            executor(resolve, reject);
        } catch (e) {
            reject(e);
        }
    }

    then(onFulfilled, onRejected) {
        if (this.status === FULFILLED_STATUS) {
            onFulfilled(this.value);
        } else if (this.status === REJECTED_STATUS) {
            onRejected(this.reason);
        } else if (this.status === PENDING_STATUS) {
            this.onFulfillCallbacks.push(() => {
                onFulfilled(this.value);
            })
            this.onRejectCallbacks.push(() => {
                onRejected(this.reason);
            })
        }
    }
}