当前位置: 首页 > news >正文

JS手写代码篇---手写Promise

4、手写promise

Promise 是一个内置对象,用于处理异步操作。Promise 对象表示一个尚未完成但预期将来会完成的操作。

Promise 的基本结构

一个 Promise 对象通常有以下状态:

  • pending(进行中):初始状态,既不是成功也不是失败。
  • fulfilled(已成功):操作成功完成。
  • rejected(已失败):操作失败。

promise原生代码:

      let promise = new Promise((resolve, reject) => {setTimeout(() => {resolve("下次一定");})});// then的用法promise.then((result) => {console.log(result);},(error) => {console.log(error);}).then((result) => {console.log(result);},(error) => {console.log(error);});

(1).初始结构

使用promise的基本结构:

    let promise = new Promise((resolve, reject) => {resolve("下次一定");});

先创建一个Promise实例,传入一个函数,函数有两个参数,而且promise是有三种状态的,执行reject还是resolve都要根据promise的状态来定

    //    因为promise的创建是:promise = new Promise(() => {})// 所以原生promose我们使用类class Commitment{// prmise有三种状态,全局定义static PENDING = "待定";static FULFILLED = "成功";static REJECTED = "拒绝";// promise一般会传入一个函数且参数为resolve和rejectconstructor(func){// 状态this.status = Commitment.PENDING;// 结果this.result = null;this.error = null;// this调用自身的方法func(this.resolve , this.reject)}// resolveresolve(result){// 判断状态if(this.status === Commitment.PENDING){Commitment.status = Commitment.FULFILLED;this.result = result;}}// rejectreject(error){if(this.status === Commitment.PENDING){Commitment.status = Commitment.REJECTED;this.error = error;}}}

(2).this指向

但是我们测试发现了问题:

promise自己写.html:38 Uncaught TypeError: Cannot read properties of undefined (reading 'status')at reject (promise自己写.html:38:21)at promise自己写.html:49:9at new Commitment (promise自己写.html:24:13)at promise自己写.html:47:21

Cannot read properties of undefined (reading ‘status’):this已经跟丢了

解决class的this指向问题:箭头函数、bind或者proxy

      constructor(func){// 状态this.status = Commitment.PENDING;// 结果this.result = null;this.error = null;// this调用自身的方法,确保这些方法在被调用时,this 的值指向当前的 Commitment 实例func(this.resolve.bind(this) , this.reject.bind(this));}
  • bind(this) 会创建一个新的函数,这个新函数的 this 值被永久绑定到当前 Commitment 实例(即 this 指向当前的 Commitment 对象)。
  • 这样,无论 resolvereject 方法在哪里被调用,this 始终指向 Commitment 实例,确保你可以正确访问实例的属性和方法(如 this.statusthis.result 等)。

(3).then

传入两个参数,一个是成功的回调,一个是失败的回调,但是还要判断条件

  promise.then((result) => {console.log(result);},(error) => {console.log(error);})
        then(onFULFILLED , onREJECTED){// 判断状态if(this.status === Commitment.FULFILLED){// 执行成功的回调onFULFILLED(this.result);}if(this.status === Commitment.REJECTED){// 执行失败的回调onREJECTED(this.error);}}

(4).执行异常

1、执行报错

   // 测试const promise = new Commitment((resolve, reject) => {throw new Error("我报错啦");});

抛出错误,要识别

        // promise一般会传入一个函数且参数为resolve和rejectconstructor(func){// 状态this.status = Commitment.PENDING;// 结果this.result = null;this.error = null;// 在执行之前try...catch捕获错误try{// this调用自身的方法,确保这些方法在被调用时,this 的值指向当前的 Commitment 实例func(this.resolve.bind(this) , this.reject.bind(this));}catch(error){// 捕获错误this.reject(error);}}

2、当传入的then参数不为函数的时候

// 测试const promise = new Commitment((resolve, reject) => {resolve("成功了");});promise.then (undefined,//成功error => { console.log("失败:", error.message); } // 失败回调(可选))

我们会发现它报错了,解决方法就是判断类型

promise自己写.html:57 Uncaught TypeError: onFULFILLED is not a functionat Commitment.then (promise自己写.html:57:17)at promise自己写.html:72:13
        // then方法:传入两个参数,一个是成功的回调,一个是失败的回调// 但是还要判断条件then(onFULFILLED , onREJECTED){// 判断状态以及是否为函数if(this.status === Commitment.FULFILLED && typeof onFULFILLED === 'function'){// 执行成功的回调onFULFILLED(this.result);}if(this.status === Commitment.REJECTED && typeof onREJECTED === 'function'){// 执行失败的回调onREJECTED(this.error);}}

(5)异步

then实现异步–setTimeOut

     // then方法:传入两个参数,一个是成功的回调,一个是失败的回调// 但是还要判断条件then(onFULFILLED , onREJECTED){// 判断状态以及是否为函数if(this.status === Commitment.FULFILLED && typeof onFULFILLED === 'function'){// 执行成功的回调onFULFILLED(this.result);}if(this.status === Commitment.REJECTED && typeof onREJECTED === 'function'){// 执行失败的回调onREJECTED(this.error);}}

resolve是异步的,then也是调用的

原生的promise:

 console.log("第一步");let promise = new Promise((resolve, reject) => {console.log("第二步");setTimeout(() => {resolve("下次一定");console.log("第四步");})});// then的用法promise.then((result) => {console.log(result);},(error) => {console.log(error);})console.log("第三步");
第一步
第二步
第三步
第四步
下次一定

但是手写promise

   console.log("第一步");const promise = new Commitment((resolve, reject) => {console.log("第二步");setTimeout(() => {  //执行thenresolve("成功了");console.log("第四步");}, 0);});promise.then (result => {console.log("成功"  , result.message); },//成功error => { console.log("失败:", error.message); } // 失败回调(可选))console.log("第三步");
第一步
第二步
第三步
第四步

原因:then中状态判断的问题,settimeout之后它就执行then方法了,但是此时的状态还是待定,但是then里面并没有处理待定状态

(6)回调保存

解决:判定待定状态,保留then里面的函数,所以我们要用数组保存函数

但是我们发现还是有问题resolve和reject是在事件循环末尾执行的,他们也要添加resolve和reject

<script>//    因为promise的创建是:promise = new Promise(() => {})// 所以原生promose我们使用类class Commitment {// prmise有三种状态,全局定义static PENDING = "待定";static FULFILLED = "成功";static REJECTED = "拒绝";// promise一般会传入一个函数且参数为resolve和rejectconstructor(func) {// 状态this.status = Commitment.PENDING;// 结果this.result = null;this.error = null;//   数组:用于保存成功和失败的回调this.onFulfilledCallbacks = [];//新增this.onRejectedCallbacks = [];//新增// 在执行之前try...catch捕获错误try {// this调用自身的方法,确保这些方法在被调用时,this 的值指向当前的 Commitment 实例func(this.resolve.bind(this), this.reject.bind(this));} catch (error) {// 捕获错误this.reject(error);}}// resolveresolve(result) {setTimeout(() => {// 判断状态if (this.status === Commitment.PENDING) {this.status = Commitment.FULFILLED;this.result = result;// 执行成功的回调--新增this.onFulfilledCallbacks.forEach((callback) => {callback(result);});}});}// rejectreject(error) {setTimeout(() => {if (this.status === Commitment.PENDING) {this.status = Commitment.REJECTED;this.error = error;// 执行失败的回调--新增this.onRejectedCallbacks.forEach((callback) => {callback(error);});}});}// then方法:传入两个参数,一个是成功的回调,一个是失败的回调// 但是还要判断条件then(onFULFILLED, onREJECTED) {// 判断状态以及是否为函数//   如果是待定,就要保存函数到数组里面--新增if (this.status === Commitment.PENDING) {this.onFulfilledCallbacks.push(onFULFILLED);this.onRejectedCallbacks.push(onREJECTED);}if (this.status === Commitment.FULFILLED &&typeof onFULFILLED === "function") {// then是异步的setTimeout(() => {// 执行成功的回调onFULFILLED(this.result);});}if (this.status === Commitment.REJECTED &&typeof onREJECTED === "function") {// then是异步的setTimeout(() => {// 执行失败的回调onREJECTED(this.error);});}}}// 测试console.log("第一步");const promise = new Commitment((resolve, reject) => {console.log("第二步");setTimeout(() => {resolve("成功了");console.log("第四步");}, 0);});promise.then((result) => {console.log(result);}, //成功(error) => {console.log(error);} // 失败回调(可选));console.log("第三步");</script>

(7)链式

promise的链式是新建一个promise对象,我们直接返回this就好了

 then(onFULFILLED, onREJECTED) {// 判断状态以及是否为函数//   如果是待定,就要保存函数到数组里面if (this.status === Commitment.PENDING) {this.onFulfilledCallbacks.push(onFULFILLED);this.onRejectedCallbacks.push(onREJECTED);}if (this.status === Commitment.FULFILLED &&typeof onFULFILLED === "function") {// then是异步的setTimeout(() => {// 执行成功的回调onFULFILLED(this.result);});}if (this.status === Commitment.REJECTED &&typeof onREJECTED === "function") {// then是异步的setTimeout(() => {// 执行失败的回调onREJECTED(this.error);});}return this; // 返回当前的promise对象}}

为什么直接返回this可以实现回调呢???

方法调用和返回值

在 JavaScript 中,方法的调用(例如 obj.method())会返回方法的返回值。

如果方法返回 this(即对象本身),那么调用该方法后,你仍然持有对该对象的引用。

链式调用的实现

当你调用

obj.method1().method2()

时:

obj.method1()被调用,并返回obj(因为 method1返回this)。

然后 method2()被调用,其调用者仍然是obj`。

这样,你可以连续调用多个方法,形成链式调用。

**总结:**手写 Promise 的核心在于实现状态管理、异步回调和链式调用。首先,Promise 有三种状态(pending/fulfilled/rejected),通过构造函数接收执行器函数,并用 resolvereject 更新状态。

关键点包括:**状态管理:**初始为 pending,调用 resolvereject 后不可逆地变为 fulfilledrejected异步回调:then 方法需异步执行回调(用 setTimeout),若状态为 pending,需将回调存入数组,待状态变更后遍历执行。**错误捕获:**构造函数中用 try/catch 捕获执行器函数的同步错误,并调用 reject链式调用:then 返回 this,使后续 then 能继续绑定回调,形成链式调用。

最终实现需确保:

  • 状态变更后异步触发回调。
  • 回调参数类型检查(非函数则忽略)。
    象的引用。

相关文章:

  • 【NLP】基于JointBERT的意图识别
  • 基于JDBC的信息管理系统,那么什么是JDBC呢?什么又是DAO类?
  • DDI核心网络服务是什么意思?有什么用?
  • 模板初阶【C++】
  • drop tablespace XXX including contents and datafiles删除表空间后,磁盘空间不释放
  • LlamaIndex
  • 46页 @《人工智能生命体 新启点》中國龍 原创连载
  • 【209. 长度最小的子数组】
  • DL00988-稀疏增强数据transformer船舶AIS轨迹预测含完整数据集
  • 开源免费抓包工具:ProxyPin 的详细使用
  • [TCG] 01.QEMU TCG 概览
  • Oracle BUFFER CACHE内存不足的优化思路
  • 多线程(七)
  • BigFoot (DBM) Deadly Boss Mods
  • export和import的书写方式
  • 计算机操作系统(十)调度的概念与层次,进程调度的时机与进程的调度方式
  • 基于STM32的骑行语音播报系统
  • 3.2.3
  • 从加密到信任|密码重塑车路云一体化安全生态
  • 【VSCode】安装与 ssh 免密登录
  • 廊坊市网站建设/互联网营销师报名入口官网
  • 搜索引擎优化哪些方面/五年级上册优化设计答案
  • 怎么做网站快照/合肥网站优化软件
  • 个人网站设计图/百度搜索量统计
  • 企业做网站要注意些什么/班级优化大师网页版登录
  • 政府部门网站建设内容/企业培训课程分类