深入理解 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 的原理,还能在实际开发中写出更高效、健壮的异步代码。

相关推荐
comerzhang65517 分钟前
Web 性能的架构边界:跨线程信令通道的确定性分析
javascript·webassembly
Hooray21 分钟前
为了在 Vue 项目里用上想要的 React 组件,我写了这个 skill
前端·ai编程
咸鱼翻身了么22 分钟前
模仿ai数据流 开箱即用
前端
风花雪月_23 分钟前
🔥IntersectionObserver:前端性能优化的“隐形监工”
前端
Bigger23 分钟前
告别 AI 塑料感:我是如何用 frontend-design skill 重塑项目官网的
前端·ai编程·trae
发际线向北23 分钟前
0x02 Android DI 框架解析之Hilt
前端
zhensherlock37 分钟前
Protocol Launcher 系列:Overcast 一键订阅播客
前端·javascript·typescript·node.js·自动化·github·js
liangdabiao1 小时前
开源AI拼豆大升级 - 一键部署cloudflare page - 全免费 web和小程序
前端·人工智能·小程序
SuperHeroWu71 小时前
【鸿蒙基础入门】概念理解和学习方法论说明
前端·学习·华为·开源·harmonyos·鸿蒙·移动端
Full Stack Developme2 小时前
MyBatis-Plus 流式查询教程
前端·python·mybatis