教你如何手写一个Promise

news2025/1/24 8:21:56

想要源码的可以看这里,里面也有一些其他的知识

想要手写一个promise,首先就要了解promise,想必大家都被过一些promise的面试题,知道一些promise的用法,主要考的就是一种异步编程的思想。

了解promise

我们先来看看直接输出一个promise对象会是什么,通过代码:

var p = new Promise((resolve,reject)=>{});
console.log(p);

可以看到输出结果Promise大致由它的状态PromiseState,它的值PromiseResult和它原型上面的方法组成。

promise对象有一个函数当作参数,函数里又分别有两个参数,分别是resolve和reject,当调用resolve()时就会运行prototype上的then()方法,当调用reject()时就会运行prototype上的catch()方法,这里的then,catch都是微任务,所谓微任务就是之宏任务运行完之后所运行的任务。就好比去银行办业务,你的要办的业务相当于宏任务,等你办完后银行工作人员会推荐与你业务相关的拓展业务,这个拓展业务就相当于微任务。

promise的状态有三种:等待(pending)、已完成(fulfilled)、已拒绝(rejected),并且状态只能由等待到完成或者等待到拒接。

开始写

了解promise之后我们就能把基本的架构写出来了。

function MyPromise(fn) {
        // promise 的状态
        this.PromiseState = "pendding";
        // promise 的值
        this.PromiseResult = undefined;
        var resolve = (value) => {};
        var reject = (errValue) => {};
        if (fn) {
          fn(resolve, reject);
        }
      }

这里定义初始状态pedding,和初始值undefined,resolve,reject两个方法。

完成then

首先先完成then的成功运作,如何能让如下代码成功输出:

var p = new MyPromise((resolve, reject) => {
        resolve("resolve");
      });
      p.then((res) => {
        console.log(res);
        console.log("then执行");
      });

这里就需要完善resolve和原型对象上写then方法:

// 定义一个函数对象,用来注册then中的callback
this.thenCallback = undefined;
var resolve = (value) => {
					// 更改promise的状态和值
					if (this.PromiseState == "pendding") {
						this.PromiseState = "fulfilled";
						this.PromiseResult = value;
						if (value instanceof MyPromise) {
							value.then((res) => {
								if (this.thenCallback) {
									this.thenCallback(res);
								}
							});
						} else {
							setTimeout(() => {
								if (this.thenCallback) {
									this.thenCallback(value);
								}
							});
						}
					}
				};
MyPromise.prototype.then = function (callback) {
				return new MyPromise((resolve, reject) => {
					this.thenCallback = (value) => {
						// 在使用链式调用的时候,可能第一个调用的不是catch
						// 使用我们在做检测时会借助then来将catch的信息向下传递
						// 所以我们检测到触发thenCallback的对象是rejected时
						// 我们就继续调用下一个reject
						if (this.promiseState == "rejected") {
							reject(value);
						} else {
							var res = callback(value);
							// 这里防止中间返回是一个promise对象它会继续找then,直接让他调用reject
							if (res instanceof MyPromise && res.promiseState == "rejected") {
								res.catch((errValue) => {
									reject(errValue);
								});
							} else {
								// 这里定义给变量res在调用resolve是为解决.then()的链式调用
								resolve(res);
							}
						}
					};
				});
			};

定义一个函数对象,用来注册then中的callback,首先判断promise的状态,如果是pendding则转换成fulfilled,并将参数值赋值给promiseResult;

if (value instanceof MyPromise)是为了判断value是否是一个Promise对象,如果是就使用自己定义的then,因为then时异步执行的,所以使用setTimeout

当then链式调用时,如then().then(),第一个then中如果有返回值,那么这个返回值将会作为第二个then中的参数,所以需要每个then返回一个新的promise对象return new MyPromise()。

这里再封装一个MyPromise.resolve的快捷调用:

MyPromise.resolve = (value) => {
				return new MyPromise((resolve, reject) => {
					resolve(value);
				});
			};

完成catch

catch与then大致相同,只需要稍作修改。这里完善reject方法和原型上的catch:


this.catchCallback = undefined;
var reject = (errValue) => {
					if (this.promiseState == "pendding") {
						this.promiseState = "rejected";
						this.promiseResult = errValue;
						// 判断写没写catch()
						setTimeout(() => {
							if (this.catchCallback) {
								this.catchCallback(errValue);
							} else if (this.thenCallback) {
								this.thenCallback(errValue);
							} else {
								throw "catch is not defined!!!!";
							}
						});
					}
				};

首先判断promise的状态,如果是pendding则转换成frejected,并将参数值赋值给promiseResult;

这里有可能再调用catch前还调用了then方法,所以使用else if判断是不是,时就运行this.thenCallback(errValue);,因为之前在then会判断promise状态是不是rejected,如果是就重新调用reject()方法。

MyPromise.prototype.catch = function (callback) {
				return new MyPromise((resolve, reject) => {
					this.catchCallback = (errValue) => {
						var res = callback(errValue);
						reject(errValue);
					};
				});
			};

这里也继续封装一个MyPromise.reject的快捷调用:

MyPromise.reject = (errValue) => {
				return new MyPromise((resolve, reject) => {
					reject(errValue);
				});
			};

promise中的api,all和race

all和race传入的参数都是一个数组,all将会等最长时间结束后按数组的顺序,而race则会执行最早的那一个。

MyPromise.all = (promiseArr) => {
				let resArr = [];
				return new MyPromise((resolve, reject) => {
					promiseArr.forEach((item, index) => {
						item
							.then((res) => {
								resArr[index] = res;
								var allResolve = promiseArr.every((_item) => {
									return _item.promiseState == "fulfilled";
								});
								// 判断传过来的数组中所有promise对象状态都已完成
								if (allResolve) {
									resolve(resArr);
								}
							})
							.catch((err) => {
								reject(err);
							});
					});
				});
			};
MyPromise.race = (promiseArr) => {
				let resArr = [];
				return new MyPromise((resolve, reject) => {
					promiseArr.forEach((item, index) => {
						item
							.then((res) => {
								resolve(res);
							})
							.catch((err) => {
								reject(err);
							});
					});
				});
			};

手写promise的化没有长时间的叙述的话不好将清楚,建议找到将promise源码的视频一步一步分析

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

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

相关文章

Node.js——http模块和导出共享

个人简介 👀个人主页: 前端杂货铺 🙋‍♂️学习方向: 主攻前端方向,也会涉及到服务端 📃个人状态: 在校大学生一枚,已拿 offer(秋招) 🥇推荐学习&…

uni-app 自定义下拉框

如图&#xff1a; html&#xff1a; <view class"row-item"> <view class"lable-tit">性别&#xff1a;</view> <view class"selected-all"> <view class"drop-down-box" click"btnShowHideClick…

JavaScript DOM基础

文章目录前言一、DOM 简介1.1 什么是 DOM1.2 DOM 树二、获取元素2.1 如何获取页面元素2.2 根据 ID 获取2.3 根据标签名获取2.4 通过 HTML5 新增的方法获取2.5 获取特殊元素&#xff08;body&#xff0c;html&#xff09;三、事件基础3.1 事件概述3.2 事件三要素3.3 执行事件的步…

Ant Design Pro(5)-7.高级表格ProTable

Ant Design Pro 高级表格ProTable的使用 文章目录Ant Design Pro 高级表格ProTable的使用一. 简介1. 什么是ProTable&#xff1f;2. 何时使用ProTable&#xff1f;二. 使用1. ProTable属性及使用2. ActionRef 手动触发3. Columns 列定义4. 批量操作5. 搜索表单一. 简介 1. 什么…

【Vue】父子组件通信

[Vue]父子组件通信前言父组件向子组件传值法一: props法二: $parent子组件向父组件传值$emit$emit .sync$refsv-model前言 &#x1f6a9;&#x1f6a9;&#x1f6a9; &#x1f48e;个人主页: 阿选不出来 &#x1f4a8;&#x1f4a8;&#x1f4a8; &#x1f48e;个人简介: 一名…

【Javaweb】会话跟踪技术CookieSession

学习目录前言一.会话引入二.Cookie1.Cookie的理解2.Cookie生命周期3.Cookie有效路径4.Cookie使用细节三.Session1.Session基本原理2.Session的理解3.Session基本使用4.Session底层5.Session生命周期前言 纸上得来终觉浅&#xff0c;绝知此事要躬行 一.会话引入 什么是会话&a…

“Property or method “***“ is not defined on the instance but referenced during render.”报错的原因及解决方案

报错问题&#xff1a; 在使用vue-cli运行项目的过程中&#xff0c;在VScode中不报错&#xff0c;但在浏览器调试工具中发出 [Vue warn]: Property or method "******" is not defined on the instance but referenced during render. Make sure that this propert…

vue-day01 使用cdn引入使用

vue-day01vue?vue简明例子模板语法1. 使用{{}} Mustache语法将数据绑定到对应的实例2.使用 v-once指令3.v-html指令4.v-bind指令和v-on指令5.动态参数&#xff0c;修饰符&#xff0c;指令缩写动态参数修饰符指令缩写vue? Vue 是一套用于构建用户界面的渐进式框架。与其它大型…

前端不使用 i18n,如何优雅的实现多语言?

前言&#xff1a; 关于ERP管理系统的多语言&#xff0c;或者其他应用的多语言一直是我们比较麻烦的问题&#xff0c;大部分是使用 i18n 在代码里进行配置&#xff0c;如果想要修改语言就要自己去改代码&#xff01; 今天我们分享一下如何不使用 i18n 去实现多语言&#xff0c;用…

web前端面试高频考点——Vue的基本使用(一文掌握Vue最基础的知识点)

系列文章目录 内容参考链接Vue基本使用Vue的基本使用&#xff08;一文掌握Vue最基础的知识点&#xff09;Vue通信和高级特性Vue组件间的通信及高级特性&#xff08;多种组件间的通信、自定义v-model、nextTick、插槽&#xff09;Vue高级特性Vue的高级特性&#xff08;动态组件…

ES6遍历方法,forEach、for...in,for..of

前言 js中遍历方法很多&#xff0c;在ES6新特性中出现了很多新的遍历方法&#xff0c;使遍历数组和对象更加方便&#xff0c;下面开始列举各种方法。 1.遍历对象 1.1.for…in…循环遍历对象自身和继承的可枚举的属性&#xff08;不包括Symbol&#xff0c;因为symbol的实例是…

微信小程序开发入门与实战(数据、事件、条件)

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; 微信小程序 &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f4…

layui 的数据表单的defaultToolbar参数中筛选列,图标,打印,三个功能,调用单独拿出使用

项目场景&#xff1a; 参数之defaultToolbar&#xff1a; 在使用layui开发的过程中&#xff0c;常常会用到 数据表单 这一关键模块&#xff0c;在这里讲一下defaultToolbar:[filter,exports print]-------“头部工具栏右侧图标”&#xff0c;如何将这三个按钮调用出来&#x…

【vscode】vscode常用插件介绍

1、Angular Snippets&#xff08;angular片段&#xff09; 这个扩展为 TypeScript 和 HTML 添加了 Angular 的代码片段。 2、Auto Close Tag&#xff08;自动闭合标签&#xff09; 自动添加 HTML/XML 关闭标记。 3、Auto Rename Tag&#xff08;自动重命名标签&#xff09; 自…

Three.js基础入门系列(九)--导入3D模型

先来学习今天的知识——Three.js导入3D模型 复杂的3D模型&#xff08;比如制作一个飞机模型&#xff09;一般都是用第三方建模工具生成&#xff0c;然后加载到Three.js中。 01 常用建模制作工具 3Dmax 链接地址&#xff1a;https://www.autodesk.com.cn/products/3ds-max/over…

启动vue-element-admin 安装npm install报错npm ERR! code 128npm ERR! An unknown git error occurre

使用vue-element-admin前端项目&#xff0c;前提是有nodejs环境&#xff0c;对于此环境的安装可以参考网上的博客。此博客用于记录启动项目以及遇到的问题、并解决问题的过程。1、介绍vue-element-admin是基于element-ui 的一套后台管理系统集成方案 。功能&#xff1a;https:/…

Vue基础教程(下篇)

&#x1f60a;作者简介&#xff1a;大家好&#xff0c;我是是你的大头呢&#xff0c;一名大三学生&#xff0c;考研备考中。让我们一起加油&#xff0c;一起努力&#xff01; &#x1f9d1;‍&#x1f4bb;博客主页&#xff1a;是你的大头呢 &#x1f970;欢迎关注&#x1f38a…

javascript 中搜索数组的四种方法

前端经常要通过 javaScript 来处理数组中的数据&#xff0c;其中就包括检查数组中是否包含满足特定搜索条件的单个或者多个值&#xff0c;这就需要我们关于用于确认的布尔值、数组中值得位置索引或包含所有搜索结果的单独数组等。 在 ECMAScript6 之前&#xff0c;最常用的方法…

Vue中 this.$set的用法

一、this.$set能够实现什么功能 官方解释&#xff1a;向响应式对象中添加一个属性&#xff0c;并确保这个新属性同样是响应式的&#xff0c;且触发视图更新。它必须用于向响应式对象上添加新属性&#xff0c;因为 Vue无法探测普通的新增属性 (比如 this.myObject.newProperty …

pdf在线预览 pdf.js的使用

1.官网&#xff1a;https://mozilla.github.io/pdf.js/ 2、使用方法 1&#xff09; 通过官网&#xff0c;下载pdfJs插件包&#xff0c;放至项目中&#xff1b; window.open("./js/pdfJS/web/viewer.html?fileAngularJS权威指南.pdf" );2&#xff09;将下载的pdfJS…