当前位置: 首页 > 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 能继续绑定回调,形成链式调用。

最终实现需确保:

  • 状态变更后异步触发回调。
  • 回调参数类型检查(非函数则忽略)。
    象的引用。
http://www.xdnf.cn/news/562267.html

相关文章:

  • 【软件设计师】知识点简单整理
  • 数学建模,机器决策人建模
  • HTTPS和HTTP区别
  • 693SJBH基于.NET的题库管理系统
  • 用Recommenders,实现个性化推荐
  • 基于OpenCV的物体跟踪:CSRT算法
  • 自托管互联网广播电台Airstation
  • Docker网关冲突导致容器启动网络异常解决方案
  • Linux `cat` 命令深度解析与高阶应用指南
  • C++ - 仿 RabbitMQ 实现消息队列(3)(详解使用muduo库)
  • 物流项目第六期(短信微服务——对接阿里云第三方短信服务JAVA代码实现、策略模式 + 工厂模式的应用)
  • bitbar环境搭建(ruby 2.4 + rails 5.0.2)
  • 【寻找Linux的奥秘】第七章:虚拟地址空间
  • 第16天-使用Python Pillow库常见图像处理场景
  • javaweb-html
  • mapbox进阶,手写放大镜功能
  • C语言之预处理和宏
  • SAP-ABAP:ABAP异常处理与SAP现代技术融合—— 面向云原生、微服务与低代码场景的创新实践
  • 云原生攻防4(Kubernetes基础补充)
  • word通配符表
  • Linux上conda环境安装完全手札
  • OpenHarmony外设驱动使用 (十),Sensor
  • 企业级爬虫开发全流程指南
  • elementUI 中el-date-picker和el-select的样式调整
  • CSS 文字样式全解析:从基础排版到视觉层次设计
  • spring-boot-starter-data-redis应用详解
  • C# AI(Trae工具+claude3.5-sonnet) 写前后端
  • maven快速上手
  • AI练习:混合圆
  • 【优秀三方库研读】在 quill 开源库 LogMarcos.h 中知识点汇总及讲解