手写Promise

如何手写Promise?

在JavaScript中,手写一个 Promise 类需要实现它的基本功能,包括状态管理(pending、fulfilled、rejected)和处理异步操作。我们需要实现以下几个关键部分:

  1. 状态管理Promise 有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。

  2. 处理器队列:在 Promise 变为 fulfilledrejected 之前,可以将处理器(回调函数)存储起来,在状态改变后再执行这些处理器。

  3. then 方法:用于添加处理器,在 Promise 状态改变后执行处理器。

  4. resolve 和 reject 方法:用于改变 Promise 的状态。

以下是一个基本的 Promise 实现:


class MyPromise {

    constructor(executor) {

        this.state = 'pending'; // 初始状态

        this.value = undefined; // fulfilled 或 rejected 的值

        this.handlers = []; // 存储 then 的处理器

        const resolve = (value) => {

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

                this.state = 'fulfilled';

                this.value = value;

                this.handlers.forEach(handler => handler.onFulfilled(value));

            }

        };

        const reject = (reason) => {

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

                this.state = 'rejected';

                this.value = reason;

                this.handlers.forEach(handler => handler.onRejected(reason));

            }

        };

        try {

            executor(resolve, reject);

        } catch (error) {

            reject(error);

        }

    }

    then(onFulfilled, onRejected) {

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

            const handle = (callback) => {

                try {

                    const result = callback(this.value);

                    if (result instanceof MyPromise) {

                        result.then(resolve, reject);

                    } else {

                        resolve(result);

                    }

                } catch (error) {

                    reject(error);

                }

            };

            if (this.state === 'fulfilled') {

                handle(onFulfilled);

            } else if (this.state === 'rejected') {

                handle(onRejected);

            } else {

                this.handlers.push({

                    onFulfilled: (value) => handle(onFulfilled),

                    onRejected: (reason) => handle(onRejected)

                });

            }

        });

    }

}

// 示例使用

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

    setTimeout(() => {

        resolve('成功的结果');

    }, 1000);

});

promise.then(result => {

    console.log(result); // 输出 "成功的结果"

    return '另一个结果';

}).then(result => {

    console.log(result); // 输出 "另一个结果"

}).catch(error => {

    console.error(error);

});

解释

  1. 构造函数:接受一个执行器函数 executor,该函数会立即执行,并且传递 resolvereject 函数用于改变 Promise 的状态。

  2. 状态管理Promisependingfulfilledrejected 三种状态。初始状态为 pending

  3. 处理器队列:在 Promise 变为 fulfilledrejected 之前,将处理器存储在 handlers 数组中。在状态改变后执行这些处理器。

  4. then 方法:添加处理器,并返回一个新的 Promise。在状态改变后执行处理器,并处理链式调用。

  5. 异步处理:通过 setTimeout 模拟异步操作,展示 Promise 的使用。

注意事项

  • 这是一个简化版的 Promise 实现,未处理一些复杂情况,如 then 方法中的参数不是函数、Promise 的多次调用、resolvereject 的参数是另一个 Promise 等。

  • 完整的 Promise 实现还需要处理更多的细节和边界情况,如 Promise 规范所定义的行为。

Error


node MyPromise.js

/Users/apple/Documents/doc/data/noteoftypora/Learn/MyPromise.js:71

}).catch(error => {

        ^

TypeError: promise.then(...).then(...).catch is not a function

    at Object.<anonymous> (/Users/apple/Documents/doc/data/noteoftypora/Learn/MyPromise.js:71:9)

    at Module._compile (internal/modules/cjs/loader.js:1114:14)

    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)

    at Module.load (internal/modules/cjs/loader.js:979:32)

    at Function.Module._load (internal/modules/cjs/loader.js:819:12)

    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)

    at internal/main/run_main_module.js:17:47

这个错误是因为在我们的简易 Promise 实现中,我们没有实现 catch 方法。为了支持 catch 方法,我们需要在 MyPromise 类中添加 catch 方法。

catch 方法实际上是一个特殊的 then 方法,它只接受一个 onRejected 回调函数。我们可以简单地将 catch 方法实现为一个调用 then 方法的包装器。

以下是更新后的代码,添加了 catch 方法:


class MyPromise {

    constructor(executor) {

        this.state = 'pending'; // 初始状态

        this.value = undefined; // fulfilled 或 rejected 的值

        this.handlers = []; // 存储 then 的处理器

        const resolve = (value) => {

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

                this.state = 'fulfilled';

                this.value = value;

                this.handlers.forEach(handler => handler.onFulfilled(value));

            }

        };

        const reject = (reason) => {

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

                this.state = 'rejected';

                this.value = reason;

                this.handlers.forEach(handler => handler.onRejected(reason));

            }

        };

        try {

            executor(resolve, reject);

        } catch (error) {

            reject(error);

        }

    }

    then(onFulfilled, onRejected) {

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

            const handle = (callback) => {

                try {

                    const result = callback(this.value);

                    if (result instanceof MyPromise) {

                        result.then(resolve, reject);

                    } else {

                        resolve(result);

                    }

                } catch (error) {

                    reject(error);

                }

            };

            if (this.state === 'fulfilled') {

                handle(onFulfilled);

            } else if (this.state === 'rejected') {

                handle(onRejected);

            } else {

                this.handlers.push({

                    onFulfilled: (value) => handle(onFulfilled),

                    onRejected: (reason) => handle(onRejected)

                });

            }

        });

    }

    catch(onRejected) {

        return this.then(null, onRejected);

    }

}

// 示例使用

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

    setTimeout(() => {

        resolve('成功的结果');

    }, 1000);

});

promise.then(result => {

    console.log(result); // 输出 "成功的结果"

    return '另一个结果';

}).then(result => {

    console.log(result); // 输出 "另一个结果"

}).catch(error => {

    console.error(error);

});

解释

  • catch 方法:添加了 catch 方法,该方法实际上调用了 then 方法,只是 onFulfilled 参数为 null,只处理 onRejected 回调。

现在,你可以在你的代码中使用 catch 方法了。如果在执行过程中发生错误,catch 回调会被调用。这个更新后的代码应该可以解决你遇到的问题。

完整的 Promise 实现

实现一个完整的 Promise 类,需要遵循 Promises/A+ 规范。这意味着要处理各种复杂情况,比如 thenable 对象、异步执行、链式调用等。以下是一个较为完整的 Promise 实现:


class MyPromise {

    constructor(executor) {

        this.state = 'pending'; // 初始状态

        this.value = undefined; // fulfilled 或 rejected 的值

        this.reason = undefined; // rejected 的理由

        this.onFulfilledCallbacks = []; // 存储 fulfilled 回调

        this.onRejectedCallbacks = []; // 存储 rejected 回调

        const resolve = (value) => {

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

                this.state = 'fulfilled';

                this.value = value;

                this.onFulfilledCallbacks.forEach(callback => callback(value));

            }

        };

        const reject = (reason) => {

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

                this.state = 'rejected';

                this.reason = reason;

                this.onRejectedCallbacks.forEach(callback => callback(reason));

            }

        };

        try {

            executor(resolve, reject);

        } catch (error) {

            reject(error);

        }

    }

    then(onFulfilled, onRejected) {

        // 如果 onFulfilled 或 onRejected 不是函数,则创建默认函数

        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;

        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

        // 返回一个新的 Promise,实现链式调用

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

            if (this.state === 'fulfilled') {

                setTimeout(() => {

                    try {

                        const result = onFulfilled(this.value);

                        this.resolvePromise(result, resolve, reject);

                    } catch (error) {

                        reject(error);

                    }

                });

            } else if (this.state === 'rejected') {

                setTimeout(() => {

                    try {

                        const result = onRejected(this.reason);

                        this.resolvePromise(result, resolve, reject);

                    } catch (error) {

                        reject(error);

                    }

                });

            } else if (this.state === 'pending') {

                this.onFulfilledCallbacks.push((value) => {

                    setTimeout(() => {

                        try {

                            const result = onFulfilled(value);

                            this.resolvePromise(result, resolve, reject);

                        } catch (error) {

                            reject(error);

                        }

                    });

                });

                this.onRejectedCallbacks.push((reason) => {

                    setTimeout(() => {

                        try {

                            const result = onRejected(reason);

                            this.resolvePromise(result, resolve, reject);

                        } catch (error) {

                            reject(error);

                        }

                    });

                });

            }

        });

    }

    catch(onRejected) {

        return this.then(null, onRejected);

    }

    // 处理 Promise 的解析

    resolvePromise(result, resolve, reject) {

        if (result === this) {

            return reject(new TypeError('Chaining cycle detected for promise'));

        }

        let called = false;

        if (result && (typeof result === 'object' || typeof result === 'function')) {

            try {

                let then = result.then;

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

                    then.call(result, (value) => {

                        if (called) return;

                        called = true;

                        this.resolvePromise(value, resolve, reject);

                    }, (reason) => {

                        if (called) return;

                        called = true;

                        reject(reason);

                    });

                } else {

                    resolve(result);

                }

            } catch (error) {

                if (called) return;

                called = true;

                reject(error);

            }

        } else {

            resolve(result);

        }

    }

    static resolve(value) {

        if (value instanceof MyPromise) {

            return value;

        }

        return new MyPromise((resolve) => resolve(value));

    }

    static reject(reason) {

        return new MyPromise((_, reject) => reject(reason));

    }

    static all(promises) {

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

            let resolvedCount = 0;

            const results = new Array(promises.length);

            promises.forEach((promise, index) => {

                MyPromise.resolve(promise).then(value => {

                    resolvedCount++;

                    results[index] = value;

                    if (resolvedCount === promises.length) {

                        resolve(results);

                    }

                }).catch(reject);

            });

        });

    }

    static race(promises) {

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

            promises.forEach(promise => {

                MyPromise.resolve(promise).then(resolve).catch(reject);

            });

        });

    }

}

// 示例使用

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

    setTimeout(() => {

        resolve('成功的结果');

    }, 1000);

});

promise.then(result => {

    console.log(result); // 输出 "成功的结果"

    return '另一个结果';

}).then(result => {

    console.log(result); // 输出 "另一个结果"

}).catch(error => {

    console.error(error);

});

主要功能解释

  1. 状态管理pendingfulfilledrejected 三种状态。

  2. 回调队列:在 pending 状态下,回调函数会被存储在队列中,状态改变后执行。

  3. then 方法:处理回调并返回新的 Promise,实现链式调用。

  4. catch 方法:专门处理 rejected 状态。

  5. resolvePromise:处理 Promise 解析的各种情况,支持 thenable 对象和循环引用检测。

  6. 静态方法:实现 resolverejectallrace 静态方法,支持更多操作。

这个实现遵循了 Promises/A+ 规范,可以处理大部分常见的 Promise 使用场景。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容