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

329 阅读2分钟

手写满足PromiseA+规范源码(上)后续补充

promise对象无法进行链式调用

const promise = new MyPromise((resolve, reject) => {
    resolve("hello");
});
promise.then().then().then().then(value => {
    return value;
}).then((value) => {
    console.log("fulfilled", value)
}, (reason) => {
    console.log("rejected", reason)
})

问题分析

  • 在promiseA+规范 2.2.7 then must return a promise [3.3].在then方法执行完后必须返回Promise对象,这样就可以进行链式调用。
  • 需要对上一个then函数返回的值x进行接收,这边需要对x的类型进行判断和处理,这边封装resolvePromise方法进行处理,这边先假定x为普通值处理,在下面会详细介绍该函数。
  • 需要对then中的参数为空时进行值传递。

解决方案

  • then方法执行完后需要返回一个promise对象。
  • then方法中的参数onFulFilled如果为函数则将其本身赋值,否则就将值往下传递,如果onRejected为函数则赋值本身,否则抛出异常原因;

示例2:

   then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => value;
        onRejected = 
            typeof onRejected === "function" ? onRejected : (reason) => { throw reason };

        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED_STATUS) {
                try {
                    let x = onFulfilled(this.value);
                    resolve(x);
                } catch (e) {
                    reject(e);
                }
            }
            ...
        });
        return promise2;
    }  

继续完善上述代码

问题背景

  • x返回为promise时,需要对promise进一步处理 ,这边封装resolvePromise方法
    

调用方式

const promise = new MyPromise((resolve, reject) => {
    resolve("hello");
});
promise.then(value => {
    return new MyPromise((resolve, reject) => {
        resolve(new MyPromise((resolve, reject) => {
            resolve(new MyPromise((resolve, reject) => {
                resolve('success');
            }))
        }))
    })
}).then((value) => {
    console.log("fulfilled", value)
}, (reason) => {
    console.log("rejected", reason)
})

如果按示例2的方法,打印的为 fulfilled MyPromise {status: "fulfilled", value: MyPromise, reason: undefined, onFulfillCallbacks: Array(0), onRejectCallbacks: Array(0)},正确应该返回为fulfilled success。

示例三

修改then方法,新增resolvePromise方法,对返回值x进行处理。

resolvePromise方法介绍

首先需要判断x是否为promise对象,如果是则进一步获取promise中的返回值,否则直接resolve即可。
需要判断x和promise是否相等,如果是则会出现循环引用的情况。
判断promise方法,不为null且类型为object或者function,并存在then方法。
由于可能进一步存在嵌套promise,则需要递归进行调用resolvePromise。

循环引用调用方式

const promise = new MyPromise((resolve, reject) => {
    resolve("hello");
});
const promise2 = promise.then(value => {
    return promise2;
});
promise2.then((value) => {
    console.log(value);
})

优化后代码

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

function resolvePromise(promise, x, resolve, reject) {
    if (promise === x) {
        // 避免循环引用
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
    }
    let called;
    if (x !== null && (["function", "object"].includes(typeof x))) {
        // 判断当前x的类型是否为Promise
        try {
            let then = x.then;
            if (typeof then === "function") {
                then.call(x, y => {
                    if (called) return;
                    called = true;
                    // y 仍为一个promise 需要递归调用
                    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);
    }
}