返回

JavaScript的承诺让你我相约,让这世界精彩绽放

前端

深入理解Promise

在前端开发中,处理异步操作是一项常见的任务。从HTTP请求到本地存储访问,无处不在。Promise提供了一种更加灵活且易于管理的方式来处理这些异步操作。它代表了一个还未完成的计算,并可以注册回调函数,从而在未来某个时间点得到结果或异常。

Promise的核心概念

  1. 状态:一个Promise有三种状态——未定态(pending)、已成功态(fulfilled)和已失败态(rejected)。一旦状态确定,就不会再改变。
  2. 值/原因:当Promise完成时,它会有一个值或错误原因。如果Promise已经成功,则该值为结果;如果已被拒绝,则这个值是导致其被拒绝的原因。
  3. then方法:通过.then()可以注册处理成功的回调函数和失败的回调函数。

Promise的基本用法

const promise = new Promise((resolve, reject) => {
    // 异步操作,比如setTimeout或者fetch等
    setTimeout(() => {
        const data = "数据加载成功";
        resolve(data);  // 成功时调用resolve,传递结果
    }, 1000);
});

promise.then(
    (result) => console.log(result), 
    (error) => console.error(error)
);

手写Promise实现

深入理解了基本概念后,不妨尝试手动实现一个简单的Promise。

完整的手写代码示例

class MyPromise {
    constructor(executor) {
        this.state = 'pending';  // 初始状态是未定态
        this.value = undefined;  // 成功或失败的结果值
        this.onFulfilledCallbacks = [];  // 存储成功的回调函数
        this.onRejectedCallbacks = [];   // 存储失败的回调函数

        const resolve = (value) => {
            if(this.state === 'pending') {
                this.value = value;
                this.state = 'fulfilled';
                setTimeout(() => {  // 确保所有.then方法异步执行
                    this.onFulfilledCallbacks.forEach(callback => callback(value));
                });
            }
        };

        const reject = (reason) => {
            if(this.state === 'pending') {
                this.value = reason;
                this.state = 'rejected';
                setTimeout(() => {  // 确保所有.then方法异步执行
                    this.onRejectedCallbacks.forEach(callback => callback(reason));
                });
            }
        };

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

    then(onFulfilled, onRejected) {
        return new MyPromise((resolve, reject) => {
            if(this.state === 'fulfilled') {
                setTimeout(() => {
                    try {
                        const result = onFulfilled ? onFulfilled(this.value) : this.value;
                        resolve(result);
                    } catch (error) {
                        reject(error);
                    }
                });
            }

            if(this.state === 'rejected') {
                setTimeout(() => {
                    try {
                        const result = onRejected ? onRejected(this.value) : this.value;
                        resolve(result);  // 注意这里使用resolve,因为onRejected返回的是成功结果
                    } catch (error) {
                        reject(error);
                    }
                });
            }

            if(this.state === 'pending') {
                this.onFulfilledCallbacks.push((value) => {
                    setTimeout(() => {
                        try {
                            const result = onFulfilled ? onFulfilled(value) : value;
                            resolve(result);
                        } catch (error) {
                            reject(error);
                        }
                    });
                });

                this.onRejectedCallbacks.push((reason) => {
                    setTimeout(() => {
                        try {
                            const result = onRejected ? onRejected(reason) : reason;
                            resolve(result);  // 注意这里使用resolve,因为onRejected返回的是成功结果
                        } catch (error) {
                            reject(error);
                        }
                    });
                });
            }
        });
    }

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

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

使用手写Promise

const myPromise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        if(true) {  // 模拟成功情况
            resolve("成功");
        } else {
            reject(new Error("失败"));
        }
    }, 1000);
});

myPromise.then(
    (result) => console.log(result), 
    (error) => console.error(error)
);

MyPromise.resolve("直接成功").then(console.log);
MyPromise.reject(new Error("直接拒绝")).catch(console.error);  // 注意使用.catch()

安全建议

  • 使用try-catch包裹异步操作,避免意外错误中断执行。
  • 在链式调用中谨慎处理error,确保每个.then()都有对应的.catch()或在链末尾添加catch()来捕捉可能的错误。

通过理解和实现Promise,开发者可以更好地掌握JavaScript中的异步编程机制,从而编写出更加高效和易于维护的代码。