前端开发系列131-进阶篇之Promise源码实现

本文介绍参考[PromiseA+]规范来实现一个符合规范的Promise库。

上面是ES6+实现的Promise核心方法,其整体结构也可以通过下面的打印查看

  /* 01-打印Promise类的内容(静态方法) */
  console.dir(Promise)

  /* 打印输出(已经省略部分内容) */
  // length: 1                      期望形参数量((resolve,reject)=>{})
  // name: "Promise"                类(构造函数)的名字
  // prototype: Promise             原型对象
  //    then: ƒ then()              then处理函数
  //    catch: ƒ catch()            catch处理函数
  //    finally: ƒ finally()        完成的处理函数
  //    constructor: ƒ Promise()    原型的构造器属性
  // race: ƒ race()                 异步任务并发先执行完
  // reject: ƒ reject()             包装为reject     
  // resolve: ƒ resolve()           包装为resolve
  // all: ƒ all()                   异步任务并发都执行完
  // allSettled: ƒ allSettled()
  // Symbol(Symbol.species): (...)
  // Symbol(Symbol.toStringTag): "Promise"

Promises/A+ 规范约定的Promise的实现逻辑和核心代码。

/* 核心注解 */
/* 1、Promise应该被设计为一个类(构造函数) */
/* 2、Promise存在三种状态,分别是pending(等待)、rejected(失败) 和 resolved(成功)。*/
/* 3、Promise类(构造函数)接收一个“拥有两个函数参数的函数”作为参数,我们可以称之为执行器函数(executor)立即执行。*/
/* 4、Promise类(构造函数)内部应该以私有函数的方式来是实现reject和resolve函数。 */
/* 5、Promise内部考虑到异步任务的执行(譬如定时器)Promise状态无法立即完成等待->成功|失败的切换,使用注册/订阅模式*/
/* 6、Promise的then方法处理失败、成功、等待态(如果存在异步任务)的Promise后续任务。 */
/* 7、Promise的then方法应该实现链式调用,实现的策略是总是返回一个新的Promise对象 */

const PENDING = "PENDING";
const RESOLVED = "RESOLVED";
const REJECTED = "REJECTED";

function resolvePromise(promise, x, resolve, reject) {

    /* 1、死循环处理 */
    if (promise === x) {
        reject(new TypeError("# Chaining cycle detected for promise #<Promise>"))
    }

    let called = false;
    /* 2、区分返回值是基本值和(Promise)的情况*/
    if ((typeof x === "object" && x != null) || typeof x === "function") {
        try {
            let then = x.then;
            if (typeof then === "function") {
                then.call(x, y => {
                    if (called) return;
                    called = true;
                    resolvePromise(promise, y, resolve, reject); /* 递归调用 */
                }, r => {
                    if (called) return;
                    called = true;
                    reject(r);
                })
            } else {
                resolve(x);
            }
        } catch (e) {
            if (called) return;
            called = true;
            reject(e);
        }
    } else {
        resolve(x);
    }
}

class Promise {
    constructor(executor) {
        this.status = PENDING;
        this.value = this.reason = undefined;
        this.rejectedCallBacks = [];
        this.resolvedCallBacks = [];

        /* reject 和 resolve 应该被实现为私有函数 */
        let resolve = (val) => {

            if (val instanceof Promise) {
                return val.then(resolve, reject);
            }

            if (this.status === PENDING) {
                this.status = RESOLVED;
                this.value = val;
                this.resolvedCallBacks.forEach(fn => fn());
            }
        }

        let reject = (val) => {
            if (this.status === PENDING) {
                this.status = REJECTED;
                this.reason = val;
                this.rejectedCallBacks.forEach(fn => fn());
            }
        }

        /* 执行器函数应该立即执行,并进行异常处理 */
        try {
            executor(resolve, reject);
        } catch (e) {
            reject(e);
        }
    }
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v;
        onRejected = typeof onRejected === "function" ? onRejected : e => { throw e }

        let promise = new Promise((resolve, reject) => {
            if (this.status === RESOLVED) {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value);
                        resolvePromise(promise, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);

            }

            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason);
                        resolvePromise(promise, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }

            if (this.status === PENDING) {
                this.rejectedCallBacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason);
                            resolvePromise(promise, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                })

                this.resolvedCallBacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(promise, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                })
            }
        })
        return promise;
    }
}

/* 基准测试 */
Promise.defer = Promise.deferred = function() {
    let dfd = {};
    dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    })
    return dfd;
}

module.exports = Promise;

规范基准测试

npm install promises-aplus-tests g
cd dist
promises-aplus-tests Promise.js

Promise还有一些诸如catch和resolve等方法,下面简单给出它们的实现代码。

class Promise{
    /* .... */
    catch (errCallBack) {
        return this.then(null, errCallBack); /* 为了支持链式调用,此处需要return */
    }
    static resolve(data) {
        return new Promise((resolve, reject) => {
            resolve(data)
        })
    }
    static reject(err) {
        return new Promise((resolve, reject) => {
            reject(err);
        })
    }
    finally(callBack) {
        return this.then((value) => {
            return Promise.resolve(callBack()).then(() => value);
        }, reason => {
            return Promise.resolve(callBack()).then(() => { throw reason });
        })
    }
}

posted on 2022-12-18 09:43  文顶顶  阅读(46)  评论(0编辑  收藏  举报

导航