深入理解 JavaScript Promise 的高效实现

引言

在现代 JavaScript 开发中,Promise 是异步操作的核心工具。无论是简单的回调替代,还是复杂的异步任务管理,Promise 都提供了一种简洁、高效的方式。然而,理解其内部实现和优化点不仅有助于掌握异步编程的本质,也能提升代码的性能与可维护性。

本文将探索如何实现一个高效、功能完善的 Promise,并剖析其中的核心机制与优化细节。


Promise 的核心机制

Promise 的底层基于状态机思想,其状态具有以下特性:

  1. 三种状态

    • pending(初始状态):表示异步操作尚未完成。
    • fulfilled(已完成):表示异步操作成功完成。
    • rejected(已拒绝):表示异步操作失败。
  2. 不可逆性

    • 状态只能从 pending 转为 fulfilledrejected,一旦变更,状态将无法再次改变。
  3. 异步回调触发

    • 注册的回调函数(通过 thencatch)必须在状态变更后异步执行,符合 JavaScript 事件循环的微任务调度规则。

优化后的 Promise 实现

以下是优化版 Promise 的完整实现,涵盖了基本功能、链式调用、静态方法等,同时对性能和易用性进行了提升。

javascript 复制代码
class OptimizedPromise {
    constructor(executor) {
        this.state = "pending"; // 初始状态
        this.value = undefined; // 成功的值
        this.reason = undefined; // 失败的原因
        this.callbacks = []; // 存储回调函数

        const resolve = (value) => {
            if (this.state === "pending") {
                this.state = "fulfilled";
                this.value = value;

                queueMicrotask(() => {
                    this.callbacks.forEach(({ onFulfilled }) => {
                        if (onFulfilled) onFulfilled(this.value);
                    });
                });
            }
        };

        const reject = (reason) => {
            if (this.state === "pending") {
                this.state = "rejected";
                this.reason = reason;

                queueMicrotask(() => {
                    this.callbacks.forEach(({ onRejected }) => {
                        if (onRejected) onRejected(this.reason);
                    });
                });
            }
        };

        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }

    then(onFulfilled, onRejected) {
        return new OptimizedPromise((resolve, reject) => {
            const handleCallback = () => {
                try {
                    if (this.state === "fulfilled") {
                        if (onFulfilled) {
                            const result = onFulfilled(this.value);
                            resolve(result instanceof OptimizedPromise ? result : result);
                        } else {
                            resolve(this.value);
                        }
                    } else if (this.state === "rejected") {
                        if (onRejected) {
                            const result = onRejected(this.reason);
                            resolve(result instanceof OptimizedPromise ? result : result);
                        } else {
                            reject(this.reason);
                        }
                    }
                } catch (error) {
                    reject(error);
                }
            };

            if (this.state === "pending") {
                this.callbacks.push({
                    onFulfilled: handleCallback,
                    onRejected: handleCallback,
                });
            } else {
                queueMicrotask(handleCallback);
            }
        });
    }

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

    finally(callback) {
        return this.then(
            (value) => {
                callback();
                return value;
            },
            (reason) => {
                callback();
                throw reason;
            }
        );
    }

    static resolve(value) {
        return new OptimizedPromise((resolve) => resolve(value));
    }

    static reject(reason) {
        return new OptimizedPromise((_, reject) => reject(reason));
    }

    static all(promises) {
        return new OptimizedPromise((resolve, reject) => {
            const results = [];
            let completed = 0;

            promises.forEach((promise, index) => {
                OptimizedPromise.resolve(promise)
                    .then((value) => {
                        results[index] = value;
                        completed++;
                        if (completed === promises.length) resolve(results);
                    })
                    .catch(reject);
            });
        });
    }

    static race(promises) {
        return new OptimizedPromise((resolve, reject) => {
            promises.forEach((promise) => {
                OptimizedPromise.resolve(promise).then(resolve).catch(reject);
            });
        });
    }
}

实现细节与优化点

1. 状态管理

通过 state 来记录当前的状态,并在 resolvereject 中处理状态流转。不可逆状态设计确保了操作的幂等性。

2. 异步调度

使用 queueMicrotask 实现微任务调度,确保回调函数异步执行,比传统的 setTimeout 更高效且符合 ECMAScript 规范。

3. 链式调用

then 方法中处理返回值类型,支持普通值和嵌套 Promise

  • 如果返回普通值,直接 resolve
  • 如果返回另一个 Promise,则等待其完成再继续。

4. 静态方法

  • resolvereject :快速创建已完成或已拒绝的 Promise
  • all :并发处理多个 Promise,返回所有完成结果。
  • race :返回第一个完成的 Promise,无论成功还是失败。

完整测试用例

测试基础功能

javascript 复制代码
const p1 = OptimizedPromise.resolve(1);
p1.then((value) => console.log("Resolved:", value)); // 输出 Resolved: 1

const p2 = new OptimizedPromise((resolve, reject) => {
    setTimeout(() => resolve(2), 100);
});
p2.then((value) => console.log("Async Resolved:", value)); // 输出 Async Resolved: 2

测试链式调用

javascript 复制代码
p1.then((value) => value * 2)
  .then((value) => new OptimizedPromise((resolve) => resolve(value + 3)))
  .then((value) => console.log("Chained Value:", value)); // 输出 Chained Value: 5

测试 allrace

javascript 复制代码
const p3 = OptimizedPromise.reject("Error!");
OptimizedPromise.all([p1, p2]).then((values) => console.log("All Resolved:", values)); // 输出 All Resolved: [1, 2]
OptimizedPromise.race([p2, p3]).catch((reason) => console.log("Race Rejected:", reason)); // 输出 Race Rejected: Error!

测试 finally

javascript 复制代码
p2.finally(() => console.log("Cleaning up...")).then((value) => console.log("Value:", value));
// 输出:
// Cleaning up...
// Value: 2

总结

这份优化后的 Promise 实现从状态管理、异步调度、链式调用到静态方法都做到了高效与规范。通过支持 finally 和链式嵌套,解决了真实开发中可能遇到的复杂场景。

核心亮点

  1. 微任务调度确保异步回调顺序。
  2. 支持所有常见静态方法(resolverejectallrace)。
  3. 完整覆盖异常处理和链式调用。

通过深入理解其实现细节,你不仅可以更好地掌握 Promise 的原理,还能在实际开发中写出更高效、健壮的异步代码。

相关推荐
一袋米扛几楼9826 分钟前
【软件安全】什么是XSS(Cross-Site Scripting,跨站脚本)?
前端·安全·xss
向上的车轮27 分钟前
Actix Web适合什么类型的Web应用?可以部署 Java 或 .NET 的应用程序?
java·前端·rust·.net
XiaoYu200240 分钟前
第1章 核心竞争力和职业规划
前端·面试·程序员
excel1 小时前
🧩 深入浅出讲解:analyzeScriptBindings —— Vue 如何分析 <script> 里的变量绑定
前端
蓝瑟1 小时前
AI时代程序员如何高效提问与开发工作?
前端·ai编程
林晓lx1 小时前
使用Git钩子+ husky + lint语法检查提高前端项目代码质量
前端·git·gitlab·源代码管理
王同学要变强2 小时前
【深入学习Vue丨第二篇】构建动态Web应用的基础
前端·vue.js·学习
社恐的下水道蟑螂2 小时前
从字符串到像素:深度解析 HTML/CSS/JS 的页面渲染全过程
javascript·css·html
程序定小飞2 小时前
基于springboot的web的音乐网站开发与设计
java·前端·数据库·vue.js·spring boot·后端·spring
Hello_WOAIAI2 小时前
2.4 python装饰器在 Web 框架和测试中的实战应用
开发语言·前端·python