手写 Promise(1)核心功能的实现

news2025/2/25 21:16:11

一:什么是 Promise

        Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。    

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

二:手写Promise

1、手写构造函数

设计思路

  • 定义类
  • 添加构造函数
  • 定义resolve/reject
  • 执行回调函数

代码实现 

    <script>
        // 创建一个类
        class wePromise{
            // 实现构造器,并且实现resolve和reject两个方法
            constructor(func) {
                const reslove = (result) => {
                    console.log('reslove-执行啦:',result);
                }
                const reject = (result) => {
                    console.log('reject-执行啦:',result);
                }

                // 执行回调函数
                func(reslove,reject)
            }
        }

        // 创建对象,调用两个方法
        const p = new wePromise((reslove,reject) => {
            console.log('执行');
            reslove('success')
            reject('reject')
        })
    </script>

运行效果

2、手写状态及原因

设计思路

  • 添加状态
  • 添加原因
  • 调整resolve/reject
  • 状态不可逆

代码实现

    <script>
        // 使用变量保存状态,便于后续使用,Ctrl + shift + p
        const PENDING = 'pending'
        const FULFILLED = 'fulfilled'
        const REJECTED = 'rejected'

        class wePromise {
            state = PENDING // 状态
            result = undefined // 原因
            // 实现构造器,并且实现resolve和reject两个方法
            constructor(func) {
                // 改状态,pending => fulfilled
                // 记录原因
                const reslove = (result) => {
                    if (this.state === PENDING) { // 锁定状态
                        this.state = FULFILLED
                        this.result = result
                    }
                }
                // 改状态,pending => rejected
                // 记录原因
                const reject = (result) => {
                    if (this.state === PENDING) { // 锁定状态
                        this.state = REJECTED
                        this.result = result
                    }
                }

                // 执行回调函数
                func(reslove, reject)
            }
        }

        // 创建对象,调用两个方法
        const p = new wePromise((reslove, reject) => {
            reslove('success')
            reject('reject')
        })
    </script>

运行效果

3、then方法--成功和失败的回调

设计思路

  • 添加实例方法
  • 参数判断
  • 执行成功/失败回调

代码实现

    <script>
        const PENDING = 'pending'
        const FULFILLED = 'fulfilled'
        const REJECTED = 'rejected'

        class wePromise {
            state = PENDING // 状态
            result = undefined // 原因
            // 构造函数
            constructor(func) {
                // 改状态,pending => fulfilled
                const reslove = (result) => {
                    if (this.state === PENDING) {
                        this.state = FULFILLED
                        this.result = result
                    }
                }
                // 改状态,pending => rejected
                const reject = (result) => {
                    if (this.state === PENDING) {
                        this.state = REJECTED
                        this.result = result
                    }
                }

                // 执行回调函数
                func(reslove, reject)
            }

            then(onFulfilled,onReject){
                // 判断传入的参数是不是函数
                onFulfilled = typeof onFulfilled === 'function'?onFulfilled : x=>x
                onReject = typeof onReject === 'function'?onReject : x=>{throw x}
                // 判断执行完成后的状态
                if(this.state === FULFILLED){
                    onFulfilled(this.result) // 返回结果
                }else if(this.state === REJECTED){
                    onReject(this.result)
                }
            }
        }

        // 创建对象,调用两个方法
        const p = new wePromise((reslove, reject) => {
            reslove('success')
            // reject('reject')
        })
        p.then(res => {
            console.log('成功回调:',res);
        },err => {
            console.log('失败回调:',err);
        })
    </script>

运行效果

4、then方法--异步和多次调用

设计思路

  • 定义实例属性
  • 保存回调函数
  • 调用成功/失败回调函数

代码实现

    <script>
        const PENDING = 'pending'
        const FULFILLED = 'fulfilled'
        const REJECTED = 'rejected'

        class wePromise {
            state = PENDING // 状态
            result = undefined // 原因
            #handlers = [] // [{onFulfilled,onReject},......]
            // 构造函数
            constructor(func) {
                // 改状态,pending => fulfilled
                const reslove = (result) => {
                    if (this.state === PENDING) {
                        this.state = FULFILLED
                        this.result = result
                        // 下面这个是异步的时候,先保存,然后到这一步执行,就取出保存的函数并且执行
                        this.#handlers.forEach(({ onFulfilled })=>{ // 解构
                            onFulfilled(this.result)
                        })
                    }
                }
                // 改状态,pending => rejected
                const reject = (result) => {
                    if (this.state === PENDING) {
                        this.state = REJECTED
                        this.result = result
                        this.#handlers.forEach(({ onReject })=>{
                            onReject(this.result)
                        })
                    }
                }

                // 执行回调函数
                func(reslove, reject)
            }

            then(onFulfilled, onReject) {
                // 判断传入的参数是不是函数
                onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
                onReject = typeof onReject === 'function' ? onReject : x => { throw x }
                // 判断执行完成后的状态
                if (this.state === FULFILLED) {
                    onFulfilled(this.result) // 返回结果
                } else if (this.state === REJECTED) {
                    onReject(this.result)
                } else if (this.state === PENDING){ // 还没有改变状态,说明是异步
                    // 保存回调函数
                    this.#handlers.push({
                        onFulfilled,onReject
                    })
                }
            }
        }

        // 创建对象,调用两个方法
        const p = new wePromise((reslove, reject) => {
            setTimeout(() => {
                reslove('success')
                // reject('reject')
            }, 2000)
        })
        p.then(res => {
            console.log('成功回调1:', res);
        }, err => {
            console.log('失败回调1:', err);
        })
        p.then(res => {
            console.log('成功回调2:', res);
        }, err => {
            console.log('失败回调2:', err);
        })
    </script>

运行效果

5、异步任务

api介绍:

  • 使用api:queueMicrotask、MutationObserve、setTimeout
  • queueMicrotask:内置的全局函数,直接queueMicrotask() 就可以调用
  • MutationObserve:内置的全局函数,比较麻烦,需要创建节点,具体看代码
  • setTimeout:内置的全局函数,定时器

设计思路

  • 定义函数
  • 调用核心api
  • 调用函数

代码实现

    <script>
        // 定义函数
        function runAsynctask(callback) {// callback 是一个回调函数
            // 调用核心api
            if (typeof queueMicrotask === 'function') { // 调用三个函数是为了解决浏览器不兼容问题,先判断是不是函数
                queueMicrotask(callback)
            } else if (typeof MutationObserver === "function") {
                const obs = new MutationObserver(callback)
                const divNode = document.createElement('div')
                obs.observe(divNode, { childList: true })
                divNode.innerHTML = '打酱油改变以下内容'
            } else {
                setTimeout(callback, 0)
            }
        }

        const PENDING = 'pending'
        const FULFILLED = 'fulfilled'
        const REJECTED = 'rejected'
        class wePromise {
            state = PENDING // 状态
            result = undefined // 原因
            #handlers = [] // [{onFulfilled,onReject},......]
            // 构造函数
            constructor(func) {
                // 改状态,pending => fulfilled
                const reslove = (result) => {
                    if (this.state === PENDING) {
                        this.state = FULFILLED
                        this.result = result
                        // 下面这个是异步的时候,先保存,然后到这一步执行,就取出保存的函数并且执行
                        this.#handlers.forEach(({ onFulfilled }) => { // 解构
                            onFulfilled(this.result)
                        })
                    }
                }
                // 改状态,pending => rejected
                const reject = (result) => {
                    if (this.state === PENDING) {
                        this.state = REJECTED
                        this.result = result
                        this.#handlers.forEach(({ onReject }) => {
                            onReject(this.result)
                        })
                    }
                }
                // 执行回调函数
                func(reslove, reject)
            }

            then(onFulfilled, onReject) {
                // 判断传入的参数是不是函数
                onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
                onReject = typeof onReject === 'function' ? onReject : x => { throw x }
                // 判断执行完成后的状态
                if (this.state === FULFILLED) {
                    runAsynctask(() => {
                        onFulfilled(this.result) // 返回结果
                    })
                } else if (this.state === REJECTED) {
                    runAsynctask(() => {
                        onReject(this.result)
                    })
                } else if (this.state === PENDING) { // 还没有改变状态,说明是异步
                    // 保存回调函数
                    this.#handlers.push({
                        onFulfilled: () => {
                            runAsynctask(() => {
                                onFulfilled(this.result) // 返回结果
                            })
                        },
                        onReject: () => {
                            runAsynctask(() => {
                                onReject(this.result)
                            })
                        }
                    })
                }
            }
        }

        console.log('top');
        // 创建对象,调用两个方法
        const p = new wePromise((reslove, reject) => {
                reslove('success')
                // reject('reject')
        })
        p.then(res => {
            console.log('成功回调:', res);
        }, err => {
            console.log('失败回调:', err);
        })
        console.log('bottom');
    </script>

运行效果

6、链式编程

设计思路

  • 返回Promise实例
  • 获取返回值
  • 处理返回值
    • 处理异常
    • 处理返回Promise(调用then方法)
    • 处理重复引用(抛出异常)

代码实现

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>7.处理返回Promise</title>
</head>

<body>
    <script>
        // 定义函数
        function runAsynctask(callback) {// callback 是一个回调函数
            // 调用核心api
            if (typeof queueMicrotask === 'function') { // 调用三个函数是为了解决浏览器不兼容问题,先判断是不是函数
                queueMicrotask(callback)
            } else if (typeof MutationObserver === "function") {
                const obs = new MutationObserver(callback)
                const divNode = document.createElement('div')
                obs.observe(divNode, { childList: true })
                divNode.innerHTML = '打酱油改变以下内容'
            } else {
                setTimeout(callback, 0)
            }
        }

        const PENDING = 'pending'
        const FULFILLED = 'fulfilled'
        const REJECTED = 'rejected'
        class wePromise {
            state = PENDING // 状态
            result = undefined // 原因
            #handlers = [] // [{onFulfilled,onReject},......]
            // 构造函数
            constructor(func) {
                // 改状态,pending => fulfilled
                const reslove = (result) => {
                    if (this.state === PENDING) {
                        this.state = FULFILLED
                        this.result = result
                        // 下面这个是异步的时候,先保存,然后到这一步执行,就取出保存的函数并且执行
                        this.#handlers.forEach(({ onFulfilled }) => { // 解构
                            onFulfilled(this.result)
                        })
                    }
                }
                // 改状态,pending => rejected
                const reject = (result) => {
                    if (this.state === PENDING) {
                        this.state = REJECTED
                        this.result = result
                        this.#handlers.forEach(({ onReject }) => {
                            onReject(this.result)
                        })
                    }
                }
                // 执行回调函数
                func(reslove, reject)
            }

            then(onFulfilled, onReject) {
                // 判断传入的参数是不是函数
                onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
                onReject = typeof onReject === 'function' ? onReject : x => { throw x }

                const p2 = new wePromise((reslove, reject) => {
                    // 判断执行完成后的状态
                    if (this.state === FULFILLED) {
                        runAsynctask(() => {
                            try {
                                // 获取返回值
                                const x = onFulfilled(this.result) // 返回结果
                                reslovePromise(p2, x, reslove, reject)
                            } catch (error) {
                                // 处理异常
                                reject(error)
                            }

                        })
                    } else if (this.state === REJECTED) {
                        runAsynctask(() => {
                            try {
                                const x = onReject(this.result)
                                reslovePromise(p2, x, reslove, reject)
                            } catch (error) {
                                reject(error)
                            }
                        })
                    } else if (this.state === PENDING) { // 还没有改变状态,说明是异步
                        // 保存回调函数
                        this.#handlers.push({
                            onFulfilled: () => {
                                runAsynctask(() => {
                                    try {
                                        const x = onFulfilled(this.result) // 返回结果
                                        reslovePromise(p2, x, reslove, reject)
                                    } catch (error) {
                                        reject(error)
                                    }
                                })
                            },
                            onReject: () => {
                                runAsynctask(() => {
                                    try {
                                        const x = onReject(this.result) // 返回结果
                                        reslovePromise(p2, x, reslove, reject)
                                    } catch (error) {
                                        reject(error)
                                    }
                                })
                            }
                        })
                    }
                })


                return p2
            }
        }

        function reslovePromise(p2, x, reslove, reject) {
            // 处理重复引用
            if (x === p2) {
                // 抛出错误
                throw new TypeError('Chaining cycle detected for promise #<Promise>')
            }
            // 处理返回的Promise
            if (x instanceof wePromise) {
                // 调用then方法
                x.then(res => reslove(res), err => reject(err))
            } else {
                // 处理返回值
                reslove(x)
            }
        }
        // 创建对象,调用两个方法
        const p = new wePromise((reslove, reject) => {
            reslove('success')
            // reject('reject')
        })
        p.then(res => {
            return new wePromise((reslove, reject) => {
                reslove(2)
            })
            // console.log('成功回调1:', res);
            // throw 'throw-error'
            // return 2
        }, err => {
            console.log('失败回调1:', err);
        }).then(res => {
            console.log('成功回调2:', res);
        }, err => {
            console.log('失败回调2:', err);
        })
    </script>
</body>

</html>

运行效果

        这个运行效果是只测了一个,有兴趣的小伙伴可以吧代码复制下来自己测。

三:总结

        截止到目前为止已经将 Promise 的核心功能实现了,还有实例方法和静态方法这些没有实现。由于篇幅过长,因此会拆分成两篇文章来完成,感觉本文还不错的小伙伴可以继续看下一篇哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1126757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[SQL开发笔记]WHERE子句 : 用于提取满足指定条件的记录

SELECT DISTINCT语句用户返回列表的唯一值&#xff1a;这是一个很特定的条件&#xff0c;假设我需要考虑很多中限制条件进行查询呢&#xff1f;这时我们就可以使用WHERE子句进行条件的限定 一、功能描述&#xff1a; WHERE子句用于提取满足指定条件的记录&#xff1b; 二、WH…

nginx快速部署一个网站服务 + 多域名 + 多端口

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

C#,数值计算——分类与推理Phylo_slc的计算方法与源程序

1 文本格式 using System; using System.Collections.Generic; namespace Legalsoft.Truffer { public class Phylo_slc : Phylagglom { public override void premin(double[,] d, int[] nextp) { } public override double dminfn(double[…

OS 处理机调度

目录 处理机调度的层次 高级调度 作业 作业控制块 JCB 作业调度的主要任务 低级调度 中级调度 进程调度 进程调度时机 进程调度任务 进程调度机制 排队器 分派器 上下文切换器 进程调度方式 非抢占调度方式 抢占调度方式 调度算法 处理机调度算法的目标 处理…

UE5 虚幻引擎中UI、HUD和UMG的区别与联系

目录 0 引言1 UI 用户界面2 HUD 用户界面3 UMG4 总结 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;UE虚幻引擎专栏&#x1f4a5; 标题&#xff1a;UE5 虚幻引擎中UI、HUD和UMG的区别与联系❣️ 寄语&#xff1a;加油&#xff0c;一次专注一件事…

Java编写图片转base64

图片转成base64 url &#xff0c; 在我们的工作中也会经常用到&#xff0c;比如说导出 word,pdf 等功能&#xff0c;今天我们尝试写一下。 File file new File("");byte[] data null;InputStream in null;ByteArrayOutputStream out null;try{URL url new URL(&…

C++初阶 入门(2)

目录 一、缺省函数 1.1什么是缺省函数 1.2为什么要有缺省函数 1.3使用缺省函数 1.4测试代码 二、函数重载 2.1什么是函数重载 2.2为什么要有函数重载 2.3什么情况构成函数重载 2.4函数重载例子及代码 三、引用 3.1什么是引用 3.2如何引用 ​3.3常引用(可略过) 3…

【宝塔面板建站】本地连接云服务器的数据库 以阿里云服务器为例子(保姆级图文)

目录 实现效果实现过程1. 获取云服务的数据库root密码 2.尝试本地连接2.1 端口放行2.2 云服务器授权本地访问MySQL权限 实现代码总结 『宝塔面板建站』分享宝塔面板从安装到实战的宝塔面板本机免云服务器免域名搭建网站等内容。 欢迎关注 『宝塔面板建站』 系列&#xff0c;持续…

Plex Media Server for Mac: 打造您的专属媒体库

在数字媒体时代&#xff0c;我们越来越依赖各种媒体应用来丰富我们的生活。其中&#xff0c;Plex Media Server for Mac以其高效、稳定和多功能性&#xff0c;逐渐成为了Mac用户们的首选。今天&#xff0c;我们就来深入探讨这款个人媒体软件的优势和应用场景。 Plex Media Serv…

【Zero to One系列】微服务Hystrix的熔断器集成

前期回顾&#xff1a; 【Zero to One系列】springcloud微服务集成nacos&#xff0c;形成分布式系统 【Zero to One系列】SpringCloud Gateway结合Nacos完成微服务的网关路由 1、hystrix依赖包 首先引入hystrix相关的依赖包&#xff0c;版本方面自己和项目内相对应即可&#…

ABB变频器使用PROFINET IO通信协议时的输入和输出介绍

ABB变频器使用PROFINET IO通信协议时的输入和输出介绍 前面和大家分享了 ABB变频器使用PROFINET IO通信模块时的激活方法 本次继续和大家分享ABB变频器使用PROFINET IO通信协议时的数据输入和输出。 如下图所示,在参数号52、53中可以设置现场总线适配器的数据输入和数据输出,…

MyBatis:配置文件

MyBatis 前言全局配置文件映射配置文件注 前言 在 MyBatis 中&#xff0c;配置文件分为 全局配置文件&#xff08;核心配置文件&#xff09; 和 映射配置文件 。通过这两个配置文件&#xff0c;MyBatis 可以根据需要动态地生成 SQL 语句并执行&#xff0c;同时将结果集转换成 …

深入探索:AbstractQueuedSynchronizer 同步器的神秘面纱

文章目录 &#x1f31f; 一、AQS的底层实现原理&#x1f34a; 1. AQS的概述&#x1f34a; 2. AQS的数据结构&#x1f389; (1) 同步状态&#x1f389; (2) 等待队列 &#x1f34a; 3. AQS的锁请求和释放过程&#x1f389; (1) 独占模式&#x1f389; (2) 共享模式 &#x1f34a…

Electron 学习

Electron基本简介 如果你可以建一个网站&#xff0c;你就可以建一个桌面应用程序。Eletron 是一个使用 JavaScript, HTML和 CSS等Web 技术创建原生程序的框架&#xff0c;它负责比较难搞的部分&#xff0c;你只需把精力放在你的应用的核心上即可。 Electron 可以让你使用纯 Jav…

s27.linux运维面试题分享

第一章 计算机基础和Linux安装 1.冯诺依曼体系结构组成部分 计算机硬件由运算器、控制器、存储器、输入设备和输出设备五大部分组成。2.Linux哲学思想(或Liunx基本原则、思想、规则) 一切都是一个文件&#xff08;包括硬件&#xff09;。小型&#xff0c;单一用途的程序。连…

分享一个月份连续的MSSA插值的GRACE level03数据集

1. 背景介绍 我们通常使用的GRACE数据包含球谐数据和mascon数据。而不管是球谐产品还是mascon产品&#xff0c;都存在月份数据的缺失&#xff0c;如下图所示&#xff08;Yi and Sneeuw, 2021&#xff09;。本专栏分享了一个利用多通道奇异谱分析&#xff08;MSSA&#…

PostgreSQL 插件 CREATE EXTENSION 原理

PostgreSQL 提供了丰富的数据库内核编程接口&#xff0c;允许开发者在不修改任何 Postgres 核心代码的情况下以插件的形式将自己的代码融入内核&#xff0c;扩展数据库功能。本文探究了 PostgreSQL 插件的一般源码组成&#xff0c;梳理插件的源码内容和实现方式&#xff1b;并介…

Apache Doris (四十七): Doris表结构变更-Schema变更

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录

报错解决:libcudart.so和libprotobuf.so链接库未找到

报错解决&#xff1a;libcudart.so和libprotobuf.so链接库未找到 libcudart.so链接库未找到原因解决方法 libprotobuf.so链接库未找到原因解决方法 此博客介绍了博主在编译软件包时遇到的两个报错&#xff0c;主要是libcudart和libprotobuf两个动态链接库未找到的问题&#xff…

频繁full GC排查

场景&#xff1a;通过prometheus去拉取通过actuator组件暴露的端点中的JVM相关指标。通过告警规则&#xff0c;检测线上服务出现频繁full gc。 ((jvm_gc_pause_seconds_count{action"end of major GC",cause!"Heap Dump Initiated GC"}- jvm_gc_pause_sec…