返回

应许之道——从实现到理解

前端

在JavaScript中,Promises作为一种强大的工具,帮助我们处理异步任务和提高代码的可读性。然而,理解它们的工作原理并不总是那么容易。本文将带你从实现的角度去探索Promises,深入理解它们的运作方式以及如何有效地使用它们。

Promises的基本原理

Promises是一个封装了异步操作结果的对象,它代表着该操作最终完成或失败的状态。Promises的实现很简单,但非常有效。让我们从头开始一步一步地构建一个Promise的实现。

class Promise {
    constructor(executor) {
        this.state = "pending";
        this.result = undefined;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];

        //立即执行executor函数,可能会同步或异步完成
        executor(
            (result) => this._resolve(result),
            (error) => this._reject(error)
        );
    }

    _resolve(result) {
        //检查当前状态,如果已经不是pending,则忽略
        if (this.state !== "pending") return;

        //将状态更改为fulfilled,并记录结果
        this.state = "fulfilled";
        this.result = result;

        //执行所有onFulfilled回调函数
        this.onFulfilledCallbacks.forEach((callback) => callback(result));
    }

    _reject(error) {
        //检查当前状态,如果已经不是pending,则忽略
        if (this.state !== "pending") return;

        //将状态更改为rejected,并记录错误信息
        this.state = "rejected";
        this.result = error;

        //执行所有onRejected回调函数
        this.onRejectedCallbacks.forEach((callback) => callback(error));
    }

    then(onFulfilled, onRejected) {
        //如果onFulfilled或onRejected不是函数,则忽略
        if (typeof onFulfilled !== "function") onFulfilled = (result) => result;
        if (typeof onRejected !== "function") onRejected = (error) => { throw error; };

        //创建新的Promise对象
        const newPromise = new Promise(() => {});

        //将当前Promise的成功回调添加到新Promise的等待列表中
        this.onFulfilledCallbacks.push((result) => {
            //在新的Promise中异步执行onFulfilled,并传递result
            setTimeout(() => {
                try {
                    const x = onFulfilled(result);
                    _resolvePromise(newPromise, x);
                } catch (error) {
                    _rejectPromise(newPromise, error);
                }
            }, 0);
        });

        //将当前Promise的失败回调添加到新Promise的等待列表中
        this.onRejectedCallbacks.push((error) => {
            //在新的Promise中异步执行onRejected,并传递error
            setTimeout(() => {
                try {
                    const x = onRejected(error);
                    _resolvePromise(newPromise, x);
                } catch (error) {
                    _rejectPromise(newPromise, error);
                }
            }, 0);
        });

        //返回新的Promise对象
        return newPromise;
    }

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

    finally(onFinally) {
        //无论Promise是成功还是失败,都执行onFinally
        return this.then(
            (result) => {
                setTimeout(() => {
                    onFinally();
                }, 0);
                return result;
            },
            (error) => {
                setTimeout(() => {
                    onFinally();
                }, 0);
                throw error;
            }
        );
    }

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

    static reject(error) {
        return new Promise((resolve, reject) => reject(error));
    }

    static all(promises) {
        return new Promise((resolve, reject) => {
            let results = [];
            let pendingPromises = promises.length;

            promises.forEach((promise, index) => {
                promise
                    .then(
                        (result) => {
                            results[index] = result;
                            pendingPromises--;
                            if (pendingPromises === 0) resolve(results);
                        },
                        (error) => reject(error)
                    );
            });
        });
    }

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

function _resolvePromise(promise, x) {
    if (promise === x) {
        throw new TypeError("Cannot resolve a promise with itself.");
    }

    if (x instanceof Promise) {
        x.then(
            (result) => _resolvePromise(promise, result),
            (error) => _rejectPromise(promise, error)
        );
    } else if (x && (typeof x === "object" || typeof x === "function")) {
        let then;
        try {
            then = x.then;
        } catch (error) {
            _rejectPromise(promise, error);
            return;
        }

        if (typeof then === "function") {
            let called = false;
            try {
                then.call(
                    x,
                    (result) => {
                        if (called) return;
                        called = true;
                        _resolvePromise(promise, result);
                    },
                    (error) => {
                        if (called) return;
                        called = true;
                        _rejectPromise(promise, error);
                    }
                );
            } catch (error) {
                if (called) return;
                _rejectPromise(promise, error);
            }
        } else {
            _resolvePromise(promise, x);
        }
    } else {
        _resolvePromise(promise, x);
    }
}

function _rejectPromise(promise, error) {
    promise.state = "rejected";
    promise.result = error;
    promise.onRejectedCallbacks.forEach((callback) => callback(error));
}

Promises的应用

Promises在JavaScript中有着广泛的应用,以下是一些常见的场景:

  • 处理异步操作。Promises可以帮助我们轻松地处理异步操作,比如网络请求、文件读写等。
  • 处理错误。Promises可以帮助我们捕获和处理错误,使我们的代码更加健壮。
  • 实现链式调用。Promises支持链式调用,这使得我们的代码更加简洁和易读。
  • 实现并发操作。Promises可以帮助我们实现并发操作,比如同时发送多个网络请求。

结论

Promises在JavaScript中发挥着重要作用,理解它们的原理和应用对于任何想深入探索现代JavaScript应用程序的开发者来说都是必不可少的。本文带你从头开始了解Promises,从它们的实现到应用,希望能够帮助你更好地理解和使用它们。