首页 > 其他分享 >Promise详解与自定义封装

Promise详解与自定义封装

时间:2024-04-07 12:34:19浏览次数:9  
标签:resolve 封装 自定义 对象 MyPromise Promise reject iterable

文章目录


概要

  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);
            }
        }
    };
})();

标签:resolve,封装,自定义,对象,MyPromise,Promise,reject,iterable
From: https://blog.csdn.net/qq_50671161/article/details/137298702

相关文章

  • Avalonia的自定义用户组件
    Avalonia中的自定义用户控件Avalonia是一个跨平台的.NETUI框架,它允许开发者使用C#和XAML来构建丰富的桌面应用程序。自定义用户控件(UserControl)是Avalonia中一种重要的组件,它允许我们将多个控件组合成一个可重用的单元。本文将介绍如何在Avalonia中定义和使用自定义用户控件,并......
  • 【C语言】:自定义类型__结构体
    这里写目录标题1、结构体的声明1.1结构体的声明1.2特殊的声明2、结构体变量的定义和初始化3、结构的自引用4、结构体内存对齐4.1结构体内存的对齐规则4.2为什么存在内存对齐4.3修改默认对齐数5、结构体传参6、结构体实现位段6.1什么是位段6.2位段的内存分配6.3......
  • 代码手术刀—自定义你的代码重构工具
    前言笔者近日在做代码仓库的存量代码缩减工作,首先考虑的是基于静态扫描的缩减,尝试使用了很多工具来对代码进行优化,例如PMD、IDEA自带的inspect功能、findBugs等。但是无一例外,要么过于“保守”,只给出扫描结果,但是无法实现一键优化,要么直接就是有bug(这里特指IDEA2023.1.5专业版-in......
  • Vue input密码输入框自定义密码眼睛icon
    我们用的饿了么UI组件库里,密码输入框的icon是固定不变的,如下所示:点击"眼睛"这个icon不变,现在需求是UI给的设计稿里,密码输入框的"眼睛"有如下两种:代码如下:<el-input:key="passwordType"ref="password"......
  • C++多线程:async、future、packaged_task、promise、shared_future的学习与使用(九)
    1、异步任务线程异步线程的概念:异步:就是非同步,同步就是必须一个一个的执行,异步可以两个事情一起干异步线程:异步线程就相当于把非关联的两件事分开找两个线程去执行,而分开的那个就是异步线程举例:例如登录信息,用户登录完毕主线程肯定是需要去及时响应用户的请求的,而系统设......
  • 从零开始的自定义神经网络设计
    目录第一部分:深度学习基础——深度学习简介前言一、深度学习的历史和重要性二、什么是神经网络?三、神经网络的基本组成部分四、基本术语和概念五、深入理解总结第一部分:深度学习基础——深度学习简介前言欢迎来到我们的从零开始的自定义神经网络设计系列!在这......
  • Typecho Joe主题自定义目录树
    1、修改主题模版编辑Joe主题文件夹public/aside.php文件<sectionid="toc"class="joe_aside__item"style="display:none;"><divclass="joe_aside__item-titlemenu_title"><svgt="1642997936013"class="......
  • .NET 8使用日志功能以及自定义日志提供程序
    .NET8使用日志功能以及自定义日志提供程序日志级别下表列出了LogLevel值、方便的Log{LogLevel}扩展方法以及建议的用法:展开表LogLevel“值”方法描述Trace0LogTrace包含最详细的消息。这些消息可能包含敏感的应用数据。这些消息默认情况下处于禁用状态,并......
  • 封装一个生成唯一ID算法的工具类
    导入maven依赖:<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.6.0</version></dependency><dependency>......
  • C语言自定义类型变量——枚举(enum)
    一.枚举的定义和声明字面意思,枚举就是一一列举,把可能的取值一一列举,在我们现实生活中有许多可以列举的事物,例如:一周七天,一年四季,性别,月份,三原色等等。当我们需要描述这些数据的时候就可以使用枚举了。其关键字为eunm.类似于结构体,联合体,定义一个枚举类型的基本形式如下:enum......