Bootstrap

手写完美版 Promise

核心逻辑,后面的 then 执不执行取决于第一个 new promise的回调函数的 resolve 回调函数的执不执行。

基础逻辑 

1、promise 构造函数接收一个回调函数,该函数会在 new Promise 时候执行。
2、promise 构造函数里会创建两个函数,第一个函数会使该 promise 对象的状态变成 resolve,另一个函数会使该 promise 对象的状态变成 reject。
3、promise 构造函数里会把这两个函数作为回调函数的参数,这样回调函数可以改变 promise 实例的状态 。

1、then 方法接收两个回调函数,这里把第一个回调函数命名为 onResolved,第二个回调函数命名为 onReject,这是因为第一个回调在 promise 实例状态变为 resolved 时调用,第二个回调在 promise 实例状态变为 reject 时调用。

2、then 方法如果返回一个新的 promise 对象,则该 then 方法后面的 then 方法的回调函数必须等待该 then 方法返回的 promise 对象的状态变为 resolved 或 reject 后才会执行。

版本一,使用 setInterval 进行监听状态的改变

<!DOCTYPE html>
<html lang="zn-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>

<script>


    class Promise {

        constructor(callback) {

            this.status = "pending";
            this.value = "";
            this.reason = "";

            const resolve = (value) => {
                this.value = value;
                this.status = 'resolve';
            }

            const reject = (value) => {
                this.reason = value;
                this.status = 'reject';
            }

            try {

                typeof callback === "function" && callback(resolve);

            } catch (error) {

                reject(error);
            }

        }
    }



    // 监听 promise 对象
    function then(target, resolveCallback, rejectCallback) {

        if (target.status === 'pending') {

            const newPromise = new Promise();

            const id1 = setInterval(() => {

                if (target.status === 'resolve') {

                    if (typeof resolveCallback === 'function') {

                        const res = resolveCallback(target.value);

                        if (res instanceof Promise) {

                            // console.log(res);

                            const id2 = setInterval(() => {

                                if (res.status === 'resolve') {

                                    newPromise.value = res.value;

                                    newPromise.status = 'resolve';

                                    clearInterval(id2);
                                }

                            }, 1);


                        } else {
                            
                            newPromise.value = res;

                            newPromise.status = 'resolve';

                        }
                    }

                    clearInterval(id1);

                }

            }, 1);

            return newPromise;

        }
    }


    const p1 = new Promise((resolve) => {

        console.log('已经执行 1');

        setTimeout(() => {
            resolve('我是 p1 的 resolve 值');
        }, 1000);

    });



    const p2 = then(p1, (res) => {

        // console.log('已经执行 2');

        console.log('p1 的 resolve 值:' + res);

        return new Promise((resolve) => {
            setTimeout(() => {
                resolve('我是 p2 的 resolve 值');
            }, 2000);
        });

    });



    const p3 = then(p2, (res) => {

        // console.log('已经执行 3');

        console.log('p2 的 resolve 值:' + res);

    });


    const p5 = then(p3, (res) => {

        console.log('已经执行 5');

        return new Promise(() => {
            setTimeout(() => {
                console.log('我是 p5 new Promise 的 resolve 回调函数');
            }, 3000);
        });
    });


</script>

</html>

版本二,使用 Promise 监听状态的改变

<!DOCTYPE html>
<html lang="zn-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>

<script>


    class Promise {

        constructor(callback) {

            this.status = "pending";
            this.value = "";
            this.reason = "";

            const resolve = (value) => {
                this.value = value;
                this.status = 'resolve';
            }

            const reject = (value) => {
                this.reason = value;
                this.status = 'reject';
            }

            try {

                typeof callback === "function" && callback(resolve);

            } catch (error) {

                reject(error);
            }

        }
    }


    // 监听 promise 对象
    function then(target, resolveCallback, rejectCallback) {

        if (target.status === 'pending') {

            const newPromise = new Promise();

            // 把对 target 的操作改成对 proxy 的操作
            // 即把 status 存储在 proxy 上
            const proxy = { status: 'pending' };

            Object.defineProperty(target, 'status', {

                get() {
                    return proxy.status;
                },
                
                set(newValue) {

                    proxy.status = newValue;

                    if (target.status === 'resolve') {

                        if (typeof resolveCallback === 'function') {

                            const res = resolveCallback(target.value);

                            // 如果函数返回值是一个 Promise 对象
                            if (res instanceof Promise) {

                                // 把对 Promise 对象的操作改成对 proxy 的操作
                                // 即把 status 存储在 proxy 上
                                const proxy = { status: 'pending' };

                                Object.defineProperty(res, 'status', {

                                    get() {
                                        return proxy.status;
                                    },

                                    set(newValue) {

                                        proxy.status = newValue;

                                        if (res.status === 'resolve') {

                                            newPromise.value = res.value;

                                            newPromise.status = 'resolve';

                                        }
                                    }

                                });

                            } else {
                                
                                newPromise.value = res;

                                newPromise.status = 'resolve';

                            }
                        }
                    }
                }
            });


            return newPromise;

        }
    }


    const p1 = new Promise((resolve) => {

        console.log('已经执行 1');

        setTimeout(() => {
            resolve('我是 p1 的 resolve 值');
        }, 1000);

    });


    console.log('我是同步函数');


    const p2 = then(p1, (res) => {

        // console.log('已经执行 2');

        console.log('p1 的 resolve 值:' + res);

        return new Promise((resolve) => {
            setTimeout(() => {
                resolve('我是 p2 的 resolve 值');
            }, 2000);
        });

    });



    const p3 = then(p2, (res) => {

        // console.log('已经执行 3');

        console.log('p2 的 resolve 值:' + res);

    });


    const p5 = then(p3, (res) => {

        console.log('已经执行 5');

        return new Promise((resolve) => {
            setTimeout(() => {
                console.log('我是 p5 new Promise 的 resolve 回调函数');
                resolve('我是 p5 的 resolve 值');
            }, 3000);
        });
    });



</script>

</html>

版本二加强,把 then 函数整合成 Promise 对象的方法

<!DOCTYPE html>
<html lang="zn-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>

<script>


    class Promise {

        constructor(callback) {

            this.status = "pending";
            this.value = "";
            this.reason = "";

            const resolve = (value) => {
                this.value = value;
                this.status = 'resolve';
            }

            const reject = (value) => {
                this.reason = value;
                this.status = 'reject';
            }

            try {

                typeof callback === "function" && callback(resolve);

            } catch (error) {

                reject(error);
            }

        }

        then(resolveCallback) {

            if (this.status === 'pending') {

                const newPromise = new Promise;

                // 把对 target 的操作改成对 proxy 的操作
                // 即把 status 存储在 proxy 上
                const proxy = { status: 'pending' };

                Object.defineProperty(this, 'status', {

                    get() {
                        return proxy.status;
                    },

                    set(newValue) {

                        proxy.status = newValue;

                        if (this.status === 'resolve') {

                            if (typeof resolveCallback === 'function') {

                                const res = resolveCallback(this.value);

                                // 如果函数返回值是一个 Promise 对象
                                if (res instanceof Promise) {

                                    // 把对 Promise 对象的操作改成对 proxy 的操作
                                    // 即把 status 存储在 proxy 上
                                    const proxy = { status: 'pending' };

                                    Object.defineProperty(res, 'status', {

                                        get() {
                                            return proxy.status;
                                        },

                                        set(newValue) {

                                            proxy.status = newValue;

                                            if (res.status === 'resolve') {

                                                newPromise.value = res.value;

                                                newPromise.status = 'resolve';

                                            }
                                        }

                                    });

                                } else {

                                    newPromise.value = res;

                                    newPromise.status = 'resolve';

                                }
                            }
                        }
                    }
                });


                return newPromise;

            }
        }
    }
    


    const p1 = new Promise((resolve) => {

        console.log('我是 new Promise 的回调函数');

        setTimeout(() => {
            resolve('我是 new Promise 的 resolve 值');
        }, 1000);

    });


    console.log('我是同步函数');


    p1.then((res) => {

        // console.log('已经执行 2');

        console.log('new Promise 的 resolve 值:' + res);

        return new Promise((resolve) => {
            setTimeout(() => {
                resolve('我是第一个 then 的 resolve 值');
            }, 1000);
        });

    }).then((res) => {

        // console.log('已经执行 3');

        console.log('第一个 then 的 resolve 值:' + res);

        // console.log('我是 p3 的 resolve');

    }).then((res) => {

        // console.log('已经执行 5');

        return new Promise((resolve) => {
            setTimeout(() => {
                console.log('我是第三个 then 的 new Promise 的 resolve 回调');
                resolve('我是 p5 的 resolve 值');
            }, 1000);
        });
    });




</script>

</html>

版本二再加强,把 resolve 函数、reject 函数、 then 回调函数放进微任务队列执行(使用 queueMicrotask 函数)

<!DOCTYPE html>
<html lang="zn-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>

<script>


    class Promise {

        constructor(callback) {

            this.status = "pending";
            this.value = "";
            this.reason = "";

            const resolve = (value) => {
                queueMicrotask(() => {
                    this.value = value;
                    this.status = 'resolve';
                });
            }

            const reject = (value) => {
                queueMicrotask(() => {
                    this.reason = value;
                    this.status = 'reject';
                });
            }

            try {

                typeof callback === "function" && callback(resolve);

            } catch (error) {

                reject(error);
            }

        }

        then(resolveCallback) {

            if (this.status === 'pending') {

                const newPromise = new Promise;

                // 把对 target 的操作改成对 proxy 的操作
                // 即把 status 存储在 proxy 上
                const proxy = { status: 'pending' };

                Object.defineProperty(this, 'status', {

                    get() {
                        return proxy.status;
                    },

                    set(newValue) {

                        proxy.status = newValue;

                        if (this.status === 'resolve') {

                            if (typeof resolveCallback === 'function') {

                                queueMicrotask(() => {

                                    const res = resolveCallback(this.value);

                                    // 如果函数返回值是一个 Promise 对象
                                    if (res instanceof Promise) {

                                        // 把对 Promise 对象的操作改成对 proxy 的操作
                                        // 即把 status 存储在 proxy 上
                                        const proxy = { status: 'pending' };

                                        Object.defineProperty(res, 'status', {

                                            get() {
                                                return proxy.status;
                                            },

                                            set(newValue) {

                                                proxy.status = newValue;

                                                if (res.status === 'resolve') {

                                                    newPromise.value = res.value;

                                                    newPromise.status = 'resolve';

                                                }
                                            }

                                        });

                                    } else {
                                        
                                        newPromise.value = res;

                                        newPromise.status = 'resolve';

                                    }

                                });


                            }
                        }
                    }
                });


                return newPromise;

            }
        }
    }



    const p1 = new Promise((resolve) => {

        console.log('我是 new Promise 的回调函数');

        setTimeout(() => {
            resolve('我是 new Promise 的 resolve 值');
        }, 1000);

    });


    console.log('我是同步函数');


    p1.then((res) => {

        // console.log('已经执行 2');

        console.log('new Promise 的 resolve 值:' + res);

        return new Promise((resolve) => {
            setTimeout(() => {
                resolve('我是第一个 then 的 resolve 值');
            }, 1000);
        });

    }).then((res) => {

        // console.log('已经执行 3');

        console.log('第一个 then 的 resolve 值:' + res);

        // console.log('我是 p3 的 resolve');

    }).then((res) => {

        // console.log('已经执行 5');

        return new Promise((resolve) => {
            setTimeout(() => {
                console.log('我是第三个 then 的 new Promise 的 resolve 回调');
                resolve('我是 p5 的 resolve 值');
            }, 1000);
        });
    });




</script>

</html>

错误版本

代码逻辑

then 返回一个新的 promise 对象(命名为 promise a),新的 promise 对象的构造函数里判断旧的 promise 对象的状态,如果旧 promise 对象的状态是等待(padding)状态,则把以下两个操作  push 进旧 promise 对象的 onResolved 回调队列


1、执行 then 的 onResolved 回调

2、执行新的 promise 对象构造函数的 resolve 回调函数,使新的 promise 对象的状态变为 resolve。


这样旧的 promise 对象只要执行了 resolve,新的 promise 对象的状态也会变为 resolve。  

错误原因

忽略了 then 的 onResolved 回调函数里有可能返回一个 新的 promise 对象。

then 的 onResolved 回调函数里有可能返回一个 新的 promise 对象(命名为 promise b),该 promise b 的回调函数有可能是异步函数,必须等待该 promise b 的回调函数有了执行结果(即 promise b 的构造函数的回调函数里执行了 resolve 回调或是 reject 回调,即 promise b 的状态变为 resolve 或 reject )后才可以执行 promise a 的构造函数的 resolve 回调(即 promise a 的状态取决于 promise b )。

错误导致的后果

错误导致的后果就是该 then 方法后面跟着的 then 方法的回调函数没有等待该 then 方法回调函数里的 promise b 状态变为 resolve 或 reject 就立刻执行了。

<!DOCTYPE html>
<html lang="zn-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>

<script>


    class MyPromise {

        // 构造函数的参数是一个回调函数
        constructor(callback) {

            this.status = "pending";
            this.value = "";
            this.reason = "";

            // 存储成功状态的回调函数
            this.onResolvedCallbacks = [];

            // 存储失败状态的回调函数
            this.onRejectedCallbacks = [];

            // 定义 resolve 函数
            // 每个 promise 对象的构造函数里都定义了一个 resolve 函数 
            // 该 resolve 函数可以修改该 promise 对象的状态为 resolve
            const resolve = (value) => {
                if (this.status == "pending") {
                    // 修改实例状态
                    this.status = "resolved";
                    this.value = value;

                    // console.log('执行 ResolvedCallback');
                    this.onResolvedCallbacks.forEach(fn => fn());
                }
            }

            // 定义 reject 函数
            // 每个 promise 对象的构造函数里都定义了一个 reject 函数 
            // reject 函数可以修改该 promise 对象的状态为 reject
            const reject = (reason) => {
                if (this.status == "pending") {
                    // 修改实例状态
                    this.status = "rejected";
                    this.reason = reason;;

                    // 执行
                    this.onRejectedCallbacks.forEach(fn => fn());
                }
            }

            try {

                // 把定义好的 resolve 函数和 reject 函数传进外部传入的回调函数
                // 执行外部传入的回调函数 
                // 这样外部传入的回调函数就可以改变该 promise 实例的 status、value 或 reason
                callback(resolve, reject);

            } catch (error) {

                reject(error);
            }

        }

        then(onResolved, onRejected) {

            onResolved = typeof onResolved === "function" ? onResolved : (value) => value;

            onRejected = typeof onRejected === "function" ? onRejected : (reason) => { throw reason };

            // 创建一个新的 promise 对象 promise2
            // 回调函数用的是箭头函数,所以回调函数里的 this 是 then 里的 this,即旧的 promise 对象
            const promise2 = new MyPromise((resolve, reject) => {

                // 如果旧的 promise 对象的状态等于 resolved
                if (this.status == "resolved") {

                    try {
                        // 执行 then 方法的 onResolved 回调函数,参数是旧的 promise 对象的值(value 属性)
                        const res = onResolved(this.value);

                        // 执行 new MyPromise 回调函数里的 resolve 回调从而修改新 promise 实例的状态(status 属性)和值(value 属性)
                        resolve(res);

                    } catch (error) {
                        reject(error);
                    }

                }

                // 如果旧的 promise 对象的状态等于 rejected
                if (this.status == "rejected") {

                    try {
                        // 执行 then 方法的 onRejected 回调函数,参数是旧的 promise 对象的 reason 属性
                        const x = onRejected(this.reason);

                        // 执行 promise2 回调函数里的 resolve 回调从而修改 promise2 实例的 status 属性和 value 属性
                        resolve(x);

                    } catch (error) {
                        reject(error);
                    }
                }

                // 如果旧的 promise 对象的状态等于 pending
                if (this.status == "pending") {

                    // 往旧 promise 对象的 onResolvedCallbacks 数组添加箭头函数
                    // 因为用的是箭头函数,所以箭头函数里的 this 值的是旧的 promise 对象 
                    this.onResolvedCallbacks.push(() => {

                        // 如果旧 promise 对象的 status 变为 resolved
                        if (this.status == "resolved") {
                            try {
                                // 执行 then 方法的 onResolved 回调函数 参数是旧 promise 对象的 value
                                const res = onResolved(this.value);

                                // 执行 new MyPromise 回调函数里的 resolve 回调从而修改新 promise 对象的 status 属性和 value 属性
                                // 参数是 then 方法的 onResolved 回调函数的返回值
                                resolve(res);

                            } catch (error) {
                                reject(error);
                            }
                        }
                    });

                    // 往 promise2 的 onRejectedCallbacks 数组添加匿名函数 
                    // 因为用的是箭头函数,所以箭头函数里的 this 值的是旧的 promise 对象 
                    this.onRejectedCallbacks.push(() => {

                        // 如果旧的 promise 对象的 status 变为 rejected
                        if (this.status == "rejected") {
                            try {
                                // 执行 then 方法的 onRejected 回调函数 参数是旧 promise 对象的 reason
                                const res = onRejected(this.reason);

                                // 执行 new MyPromise 回调函数里的 reject 回调从而修改 promise2 对象的 status 属性和 value 属性
                                // 参数是 then 方法的 onRejected 回调函数的返回值
                                resolve(res);
                            } catch (error) {
                                reject(error);
                            }
                        }
                    });

                } else {

                    console.log('清空回调数组');

                    // 执行完所有回调函数之后,清空回调数组
                    this.onResolvedCallbacks = [];
                    this.onRejectedCallbacks = [];
                }
            });

            // 返回 promise2 
            return promise2
        }

        catch(onRejected) {
            return this.then(null, onRejected);
        }
    }


    const p1 = new MyPromise((resolve, reject) => {

        setTimeout(() => {
            console.log(1);
            resolve('我是 p1 resolve 的成功');
        }, 1000);
    });


    p1.then((res) => {

        return new MyPromise((resolve, reject) => {

            setTimeout(() => {
                console.log(2);
                resolve('我是 p1 resolve 的成功 2');
            }, 1000);
        });

    }).then((res) => {
        
        return new MyPromise((resolve, reject) => {

            setTimeout(() => {
                console.log(3);
                resolve('我是 p1 resolve 的成功 3');
            }, 1000);
        });
    });


    // p1.then(1).then(value => {

    //     console.log('1');

    // }).then(value => {

    //     console.log('2');

    //     return new MyPromise((resolve, reject) => {
    //         setTimeout(() => {
    //             resolve('第二次处理结果');
    //         }, 1000);
    //     });

    // }).then(value => {

    //     //console.log(value);
    //     console.log(value);

    //     throw new Error('抛出异常');

    // }).catch(error => {

    //     console.log(error);
    // });



</script>


</html>

;