Promise详解与自定义封装


概要

  Promise是ES6异步编程的一种解决方案,可以被链式调用,解决了回调地狱问题。一个 Promise 是一个代理,它代表一个在创建 Promise 时不一定已知的值。它允许你将处理程序与异步操作的最终成功值或失败原因关联起来。这使得异步方法可以像同步方法一样返回值:异步方法不会立即返回最终值,而是返回一个 Promise,以便在将来的某个时间点提供该值。

一个 Promise 必然处于以下几种状态之一:

  • 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled):意味着操作成功完成。
  • 已拒绝(rejected):意味着操作失败。

一、Promise详解

1. 构造函数

1.1 语法

new Promise(executor)
/** 备注:
 Promise() 只能通过 new 运算符来构造。
 如果尝试在没有使用 new 的情况下调用它,会抛出 TypeError 异常。
*/

1.2 参数

executor:在构造函数中执行。它接收两个函数作为参数:resolveFuncrejectFunc

  • 如果在 executor 函数中抛出错误,则 Promise 将被拒绝,除非 resolveFunc 或 rejectFunc 已经被调用。
  • executor 通常会封装某些提供基于回调的 API 的异步操作。回调函数(传给原始回调 API 的函数)在 executor 代码中定义,因此它可以访问 resolveFunc 和 rejectFunc。
  • executor 是同步调用的(在构造 Promise 时立即调用),并将 resolveFunc 和 rejectFunc 函数作为传入参数。

1.3 返回值

  当通过 new 关键字调用 Promise 构造函数时,它会返回一个 Promise 对象。当 resolveFunc 或者 rejectFunc 被调用时,该 Promise 对象就会变为已解决(resolved)。

如果你调用 resolveFunc 或 rejectFunc 并传入另一个 Promise 对象作为参数,可以说该 Promise 对象“已解决”,但仍未“敲定(settled)”

2. 属性

2.1 [[PromiseState]]

  标识Promise对象状态(初始值pendingfulfilledrejected)。

2.2 [[PromiseResult]]

  保存处理程序与异步操作的最终成功值或失败原因,初始值undefined

3. 方法

3.1 Promise.prototype.then

3.1.1 语法
then(onFulfilled)
then(onFulfilled, onRejected)
3.1.2 参数

onFulfilled 可选

一个在此 Promise 对象被兑现时异步执行的函数。它的返回值将成为 then() 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数:
value:Promise 对象的兑现值。

onRejected 可选

一个在此 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 catch() 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数:
reason:Promise 对象被拒绝的原因

3.1.3 返回值

  立即返回一个新的 Promise 对象,该对象始终处于待定状态,无论当前 Promise 对象的状态如何。

onFulfilled 和 onRejected 处理函数之一将被执行,以处理当前 Promise 对象的兑现或拒绝。即使当前 Promise 对象已经敲定,这个调用也总是异步发生的。返回的 Promise 对象(称之为 p)的行为取决于处理函数的执行结果,遵循一组特定的规则。如果处理函数:

  • 返回一个值:p 以该返回值作为其兑现值。
  • 没有返回任何值:p 以 undefined 作为其兑现值。
  • 抛出一个错误:p 抛出的错误作为其拒绝值。
  • 返回一个已兑现的 Promise 对象:p 以该 Promise 的值作为其兑现值。
  • 返回一个已拒绝的 Promise 对象:p 以该 Promise 的值作为其拒绝值。
  • 返回另一个待定的 Promise 对象:p 保持待定状态,并在该 Promise 对象被兑现/拒绝后立即以该 Promise 的值作为其兑现/拒绝值。

3.2 Promise.prototype.catch

3.2.1 语法
catch(onRejected)
3.2.2 参数

onRejected

一个在此 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 catch() 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数:
reason:Promise 对象的拒绝值。

3.2.3 返回值

  立即返回一个新的 Promise 对象,该对象始终处于待定状态,无论当前 Promise 对象的状态如何。

如果调用了 onRejected,则返回的 promise 将根据此调用的返回值进行兑现,或者使用此调用引发的错误进行拒绝。如果当前的 promise 已兑现,则 onRejected 不会被调用,并且返回的 promise 具有相同的兑现值。

3.3 Promise.prototype.finally

3.3.1 语法
finally(onFinally)
3.3.2 参数

onFinally

一个当 promise 敲定时异步执行的函数。它的返回值将被忽略,除非返回一个被拒绝的 promise。调用该函数时不带任何参数。

3.3.3 返回值

  立即返回一个新的 Promise 对象,该对象始终处于待定状态,无论当前 Promise 对象的状态如何。

如果 onFinally 抛出错误或返回被拒绝的 promise,则新的 promise 将使用该值进行拒绝。否则,新的 promise 将以与当前 promise 相同的状态敲定(settled)。

3.4 Promise.resolve

3.4.1 语法
Promise.resolve(value)
3.4.2 参数

value

要被该 Promise 对象解决的参数。也可以是一个 Promise 对象或一个 thenable 对象。

3.4.3 返回值

  一个由给定值解决的 Promise,或者如果该值为一个 Promise 对象,则返回该对象。

用于解决的 Promise 可以处于已兑现、已拒绝或待定状态中的任何一种。例如,对一个已拒绝的 Promise 进行调用仍将返回一个已拒绝的 Promise。

3.5 Promise.reject

3.5.1 语法
Promise.reject(reason)
3.5.2 参数

reason

该 Promise 对象被拒绝的原因。

3.5.3 返回值

  返回一个已拒绝(rejected)的 Promise,拒绝原因为给定的参数。

3.6 Promise.all

3.6.1 语法
Promise.all(iterable)
3.6.2 参数

iterable

一个可迭代对象,例如 Array 或 String。

3.6.3 返回值

  一个新的 Promise 对象

其状态为:

  • 已兑现(already fulfilled),如果传入的 iterable 为空。
  • 异步兑现(asynchronously fulfilled),如果给定的 iterable 中所有的 promise 都已兑现。兑现值是一个数组,其元素顺序与传入的 promise 一致,而非按照兑现的时间顺序排列。如果传入的 iterable 是一个非空但不包含待定的(pending)promise,则返回的 promise 依然是异步兑现,而非同步兑现。
  • 异步拒绝(asynchronously rejected),如果给定的 iterable 中的任意 promise 被拒绝。拒绝原因是第一个拒绝的 promise 的拒绝原因。

3.7 Promise.any

3.7.1 语法
Promise.any(iterable)
3.7.2 参数

iterable

一个可迭代对象,例如 Array 或 String。

3.7.3 返回值

  一个新的 Promise 对象

其状态为:

  • 已拒绝(already rejected),如果传入的 iterable 为空的话。
  • 异步兑现(asynchronously fulfilled),当给定的 iterable 中的任何一个 Promise 被兑现时,返回的 Promise 就会被兑现。其兑现值是第一个兑现的 Promise 的兑现值。
  • 异步拒绝(asynchronously rejected),当给定的 iterable 中的所有 Promise 都被拒绝时。拒绝原因是一个 AggregateError,其 errors 属性包含一个拒绝原因数组。无论完成顺序如何,这些错误都是按照传入的 Promise 的顺序排序。如果传递的 iterable 是非空的,但不包含待定的 Promise,则返回的 Promise 仍然是异步拒绝的(而不是同步拒绝的)。

3.8 Promise.race

3.8.1 语法
Promise.race(iterable)
3.8.2 参数

iterable

一个可迭代对象,例如 Array 或 String。

3.8.3 返回值

  一个新的 Promise 对象

会以 iterable 中第一个敲定的 promise 的状态异步敲定。换句话说,如果第一个敲定的 promise 被兑现,那么返回的 promise 也会被兑现;如果第一个敲定的 promise 被拒绝,那么返回的 promise 也会被拒绝。如果传入的 iterable 为空,返回的 promise 就会一直保持待定状态。如果传入的 iterable 非空但其中没有任何一个 promise 是待定状态,返回的 promise 仍会异步敲定(而不是同步敲定)

二、Promise自定义封装

export default (function () {
    // 定义状态常量
    const PENDING = "pending";
    const FULFILLED = "fulfilled";
    const REJECTED = "rejected";
    
    // 定义类
    return class MyPromise{
        #PromiseState = PENDING;        // 状态
        #PromiseResult = undefined;     // 结果
        #Callbacks = [];                // 回调函数数组

        /** MyPromise 的构造函数
         * @param {Function} executor - 在构造函数中执行。它接收两个函数作为参数:resolve 和 reject
         * @returns {MyPromise} MyPromise对象
         */
        constructor(executor) {
            try {
                // 尝试执行executorb并传入resolve私有方法和reject方私有法,注意this的指向;
                executor(this.#resolve.bind(this), this.#reject.bind(this));
            } catch (e) {
                // 若executor在执行中发生异常,那么调用reject方法,e作为其拒绝值
                this.#reject(e);
            } 
            
        }

        /** then 方法
         * @param {Function} onFulfiled - 当前MyPromise对象(fulfilled)兑现时的回调函数
         * @param {Function} onRejected - 当前MyPromise对象(rejected)拒绝时的回调函数
         * @returns {MyPromise} 新MyPromise对象
         * */ 
        then(onFulfilled, onRejected) {
            return new MyPromise((resolve, reject) => {
                // 将onFulfilled,onRejected,resolve,reject打包成对像压入回调函数数组
                this.#Callbacks.push({
                    onFulfilled,
                    onRejected,
                    resolve,
                    reject
                })
                this.#callbackRun();
            })
        }

        /** catch 方法
         * @param {Function} onFulfiled - 当前MyPromise对象(rejected)拒绝时的回调函数
         * @returns {MyPromise} 新MyPromise对象
         * */ 
        catch(onRejected) {
            return new MyPromise((resolve, reject) => {
                this.#Callbacks.push({
                    onRejected,
                    resolve,
                    reject
                })
                this.#callbackRun();
            })
        }

        /** finally 方法
         * @param {Function} onFinally - 当前MyPromise对象(rejected)拒绝时或(fulfilled)兑现时的都会执行的回调函数
         * @returns {MyPromise} 新MyPromise对象
         * */
        finally(onFinally) {
            const seft = this;
            return new MyPromise((resolve, reject) => {
                const settled = seft.#PromiseState === FULFILLED ? resolve : reject;
                this.#Callbacks.push({
                    onFulfilled: onFinally,
                    onRejected: onFinally,
                    resolve() {
                        settled(seft.#PromiseResult);
                    },
                    reject
                })
                this.#callbackRun();
            })
        }

        /** resolve 静态方法
         * @param {any} value - 任意类型的值
         * @returns {MyPromise} 
         */
        static resolve(value) {
            // 如果value是MyPromise对象,那么直接返回value
            if (value instanceof MyPromise) return value;
            // 如果value非MyPromise对象,将value作为返回新MyPromise对象的兑现值
            return new MyPromise((resolve, reject) => {
                resolve(value);
            })
        }

        /** reject 静态方法
         * @param {any} reason - 任意类型的值
         * @returns {MyPromise}
         */
        static reject(reason) {
            // 将reason作为返回新MyPromise对象的拒绝值
            return new MyPromise((resolve, reject) => {
                reject(reason);
            })
        }

        /** all 静态方法
         * @param {Array} iterable - MyPromise对象数组
         * @returns {MyPromise}
         */
        static all(iterable) {
            return new MyPromise((resolve, reject) => {
                // 如果传入的iterable为空,将返回已兑现
                if (!iterable) resolve();
                else {
                    // 存储每个异步MyPromise对象的兑现值
                    let results = new Array(iterable.length);
                    let count = 0;
                    for (let i = 0; i < iterable.length; i++){
                        iterable[i].then(value => {
                            count++;
                            results[i] = value;
                            // 如果每个异步MyPromise对象都已兑现,则将results作为新MyPromise的兑现值
                            if (count == results.length) {
                                resolve(results);
                            }
                        }, reason => {
                            // 只要有一个MyPromise对象已拒绝,则将reason新MyPromise的拒绝值
                            reject(reason);
                        })
                    }
                }
            })
        }

        /** any 静态方法
         * @param {Array} iterable - MyPromise对象数组
         * @returns {MyPromise}
         */
        static any(iterable) {
            return new MyPromise((resolve, reject) => {
                if (!iterable) reject();
                else {
                    let results = new Array(iterable.length);
                    let count = 0;
                    for (let i = 0; i < iterable.length; i++){
                        iterable[i].then(value => {
                            resolve(value);
                        }, reason => {
                            count++;
                            results[i] = reason;
                            if (count == results.length) {
                                reject(results);
                            }
                        })
                    }
                }
            })
        }

        /** race 静态方法
         * @param {Array} iterable - MyPromise对象数组
         * @returns {MyPromise}
         */
        static race(iterable) {
            return new MyPromise((resolve, reject) => {
                // 如果传入的 iterable 为空,返回的MyPromise对象就会一直保持待定状态
                // terable 中第一个敲定的 promise 的状态异步敲定
                if (iterable){
                    for (let i = 0; i < iterable.length; i++){
                        iterable[i].then(value => {
                            resolve(value);
                        }, reason => {
                            reject(reason);
                        })
                    }
                }
            })
        }

        // resolve私有方法
        #resolve(value) {
            if (value instanceof MyPromise) {          
                value.then((value) => {
                    this.#settle(FULFILLED, value);
                }, reason => {
                    this.#settle(REJECTED, reason);
                })
            } else {
                this.#settle(FULFILLED, value);
            }
        }

        // reject私有方法
        #reject(reason) {
            this.#settle(REJECTED, reason);
        }

        #settle(state, result) {
            if (this.#PromiseState !== PENDING) return;
            this.#PromiseState = state;
            this.#PromiseResult = result;
            this.#callbackRun();
        }
        #callbackRun() {
            if (this.#PromiseState === PENDING) return;
            // 如果当前的MyPromise的状态发生改变,那么将回调函数数组的回调函数取出执行
            while (this.#Callbacks.length) {
                const { onFulfilled, onRejected, resolve, reject } = this.#Callbacks.shift();
                if (this.#PromiseState == FULFILLED) {
                    this.#settleRun(onFulfilled, resolve, reject);
                } else {
                    this.#settleRun(onRejected, resolve, reject);
                }
            }
        }

        #settleRun(callback, resolve, reject) {
            const settled = this.#PromiseState == FULFILLED ? resolve : reject;
            if (callback instanceof Function) {
                // 将then方法的回调函数放入微队列
                queueMicrotask(() => {
                    try {
                        const result = callback(this.#PromiseResult);
                        // 如果回调函数的返回值是一个MyPromise对象,那么result的处理结果就是新MyPromise对象的结果
                        if (result instanceof MyPromise) {
                            result.then(value => {
                                resolve(value);
                            }, reason => {
                                reject(reason);
                            })
                        } else {
                        // 如果是普通数据,将该数据设为新MyPromise对象的兑现值
                        resolve(result);
                        }
                    } catch (e) {
                        // 在执行中发生异常,那么调用reject方法,e作为其拒绝值
                        reject(e);
                    } 
                })
            } else {
                // 若为传入回调函数,那么旧MyPromise对象的结果,就是新MyPromise对象的结果
                settled(this.#PromiseResult);
            }
        }
    };
})();
  • 31
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值