一个必须知道的 Js 问题:创建一个基本的自定义 Promise 🌟

简介🌟

JavaScript 的“Promise”是管理异步操作的强大工具,但如果我们想构建自己的 Promise 版本以了解其内部工作原理,该怎么办?在这篇文章中,我们将介绍从头开始创建基本自定义 Promise 的过程,并探索各种修改以增强其功能。在这篇文章的结尾,我们对 Promise、其工作原理以及如何扩展它们有了深刻的理解。

如何构建自定义 Promise

在深入研究代码之前,让我们先分解一下创建 Promise 时需要理解的核心概念。Promise 本质上是一个占位符,用于表示现在或将来可能可用的值,通常是在异步操作完成后。

Promise 的核心组成部分:

  • 状态管理:承诺可以处于以下三种状态之一:待定⏳:承诺仍在执行中。已实现✅:承诺已成功完成。已拒绝❌:承诺已失败。
  • 回调:承诺允许我们附加成功(然后)和失败(捕获)回调,这些回调将在承诺被履行或拒绝后执行。
  • 循序渐进:建立基本的自定义承诺🏗️

    我们首先创建一个自定义 Promise,该 Promise 可以根据异步操作解析或拒绝。以下是我们的实现方法:

  • 定义状态:我们将在自定义承诺中管理状态(待定、已完成和已拒绝)。
  • 存储回调:我们将把成功和错误处理程序存储在数组中,以便承诺解决后可以稍后调用它们。
  • 解决和拒绝逻辑:我们将实现方法来改变承诺的状态并调用适当的回调。
  • 这是一个简单的实现:

    // Custom Promise constructor
    class CustomPromise {
        constructor(executor) {
            this.state = 'pending';  // Possible states: 'pending', 'fulfilled', 'rejected'
            this.value = undefined;  // Will hold the result or error
            this.successCallbacks = [];
            this.errorCallbacks = [];
    
            // Executor is the function passed to the promise
            try {
                console.log("Executing the promise... 🎯");
                executor(this._resolve, this._reject);
            } catch (error) {
                this._reject(error);
            }
        }
    
        // Custom resolve function
        _resolve = (value) => {
            if (this.state === 'pending') {
                this.state = 'fulfilled';
                this.value = value;
                console.log(`Promise resolved with: ${value} ✅`);
                this.successCallbacks.forEach(callback => callback(this.value));
            }
        }
    
        // Custom reject function
        _reject = (error) => {
            if (this.state === 'pending') {
                this.state = 'rejected';
                this.value = error;
                console.log(`Promise rejected with: ${error} ❌`);
                this.errorCallbacks.forEach(callback => callback(this.value));
            }
        }
    
        // Then method to handle successful promise resolution
        then(successCallback) {
            if (this.state === 'fulfilled') {
                successCallback(this.value);
            } else if (this.state === 'pending') {
                this.successCallbacks.push(successCallback);
            }
            return this;  // Allows chaining 🔄
        }
    
        // Catch method to handle promise rejection
        catch(errorCallback) {
            if (this.state === 'rejected') {
                errorCallback(this.value);
            } else if (this.state === 'pending') {
                this.errorCallbacks.push(errorCallback);
            }
            return this;  // Allows chaining 🔄
        }
    }

    解释📚:

  • 状态和值:我们将状态初始化为待定,将值初始化为未定义。该值将保存结果或错误,具体取决于承诺是已实现还是已拒绝。
  • 回调:我们维护两个数组,successCallbacks 和 errorCallbacks,其中存储在承诺被解决或被拒绝后应调用的回调。
  • 执行器:传递给 Promise 构造函数的执行器函数负责触发 Promise 的解决或拒绝。
  • 解决方案:_resolve 方法将状态更改为已实现并调用所有成功回调。
  • 拒绝:_reject 方法将状态改为拒绝,并调用所有错误回调。
  • 使用自定义承诺🖥️:

    现在,让我们使用自定义承诺并记录结果,以便我们可以看到承诺的实际作用:

    const myCustomPromise = new CustomPromise((resolve, reject) => {
        setTimeout(() => {
            const success = true;  // Change this to false to test rejection
    
            if (success) {
                resolve("Custom promise resolved successfully! 🎉");
            } else {
                reject("Custom promise was rejected! 😔");
            }
        }, 2000);  // 2-second delay ⏳
    });
    
    myCustomPromise
        .then((message) => {
            console.log("Inside then:", message);  // Will print if promise is resolved
        })
        .catch((error) => {
            console.error("Inside catch:", error);  // Will print if promise is rejected
        });

    预期输出:

    如果“success”变量设置为“true”,则输出将是:

    Executing the promise... 🎯
    Promise resolved with: Custom promise resolved successfully! 🎉
    Inside then: Custom promise resolved successfully! 🎉

    如果将“success”变量设置为“false”,则输出将是:

    Executing the promise... 🎯
    Promise rejected with: Custom promise was rejected! 😔
    Inside catch: Custom promise was rejected! 😔

    增强和修改🔧

    一旦我们有了自定义承诺的基本结构,我们就可以通过多种方式改进它。让我们探索一些有用的修改:

    1. 支持多个 then 和 catch 调用的链接🔄

    Promise 通常会串联起来以处理连续的异步操作。我们可以增强 `then` 方法以返回新的 Promise,从而允许串联多个处理程序。

    then(successCallback) {
        const newPromise = new CustomPromise((resolve, reject) => {
            const handleSuccess = (value) => {
                try {
                    const result = successCallback(value);
                    if (result instanceof CustomPromise) {
                        result.then(resolve).catch(reject);
                    } else {
                        resolve(result);
                    }
                } catch (error) {
                    reject(error);
                }
            };
    
            if (this.state === 'fulfilled') {
                handleSuccess(this.value);
            } else if (this.state === 'pending') {
                this.successCallbacks.push(handleSuccess);
            }
        });
        return newPromise;  // Return the new promise for chaining 🔄
    }

    2. 添加 finally 方法🧹

    无论承诺是否被解决或被拒绝,'finally' 方法都会执行回调,通常用于清理任务。

    finally(callback) {
        return this.then(
            (value) => {
                callback();
                return value;  // Pass the resolved value through
            },
            (error) => {
                callback();
                throw error;  // Pass the rejection through
            }
        );
    }

    3. 超时功能⏰

    有时,我们可能希望对 Promise 强制设置超时。如果 Promise 在给定时间内未解决,则会自动拒绝。

    timeout(ms) {
        return new CustomPromise((resolve, reject) => {
            const timer = setTimeout(() => {
                reject('Promise timed out ⏳');
            }, ms);
    
            this.then((value) => {
                clearTimeout(timer);
                resolve(value);
            }).catch((error) => {
                clearTimeout(timer);
                reject(error);
            });
        });
    }

    4. 静态解析和拒绝方法✅❌

    为了创建已经解决或拒绝的承诺,我们可以添加静态方法来模仿 JavaScript 原生的“Promise.resolve()”和“Promise.reject()”的行为。

    static resolve(value) {
        return new CustomPromise((resolve) => resolve(value));
    }
    
    static reject(error) {
        return new CustomPromise((_, reject) => reject(error));
    }

    5. 添加 all 和 race 方法⚡

    为了同时处理多个承诺,我们可以实现“all”(当所有承诺都实现时解决)和“race”(在第一个承诺解决后立即解决)。

    static all(promises) {
        return new CustomPromise((resolve, reject) => {
            const results = [];
            let completed = 0;
    
            promises.forEach((promise, index) => {
                promise.then((value) => {
                    results[index] = value;
                    completed++;
                    if (completed === promises.length) {
                        resolve(results);
                    }
                }).catch(reject);
            });
        });
    }

    结论

    创建自定义 Promise 是了解 JavaScript 如何在后台处理异步操作的绝佳方式。在这篇文章中,我们介绍了 Promise 的基本结构,添加了详细的日志来帮助我们跟踪其进度,并探索了可以实施的几种修改,以使其更加强大。从支持链式和“finally”方法到添加超时功能和处理多个 Promise,这些修改使我们的自定义 Promise 更接近 JavaScript 的原生“Promise”。

    随着我们继续尝试异步编程,构建我们自己的类似承诺的实现将为我们理解 JavaScript 并发模型的内部工作原理奠定坚实的基础。祝您编码愉快!🎉