手写Promise源码的实现思路

Promise的使用:

let promise = new Promise((resolve, reject) => {
    resolve("OK");
    // reject("Error");
});

console.log(promise);

promise.then(value => {
    console.log("success");
}, error => {
    console.log("fail");
});
  1. 定义构造函数中的两个基本属性PromiseStatePromiseResult

    function Promise() {
        this.PromiseState = "pending";
        this.PromiseResult = null;
    }
    
  2. 由于实例对象中传递的参数是一个执行器函数,并且会立即执行这个函数。

    function Promise(executor) {
        this.PromiseState = "pending";
        this.PromiseResult = null;
        
        executor();
    }
    
  3. 该执行器函数中有两个函数参数,调用任意一个函数会改变promise的状态和结果值,且状态只能改变一次。

    function Promise(executor) {
        this.PromiseState = "pending";
        this.PromiseResult = null;
        
        // 防止this指向window
        const self = this;
        function resolve(value) {
            if(self.PromiseState !== "pending") return;
            self.PromiseState = "fulfilled";
            self.PromiseResult = value;
        }
        
        function reject(reason) {
            if(self.PromiseState !== "pending") return;
            self.PromiseState = "rejected";
            self.PromiseResult = reason;
        }
        // 参数为一个函数且立即执行,该函数需要两个函数参数改变promise的状态和结果值
        executor(resolve, reject);
    }
    
  4. 还有一种情况:promise实例执行结果为抛出异常,需要让其状态为失败。

    function Promise(executor) {
        // ...
        
        // 参数为一个函数且立即执行,该函数需要两个函数参数改变promise的状态和结果值;抛出异常时状态为失败
        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }
    
  5. 在对象原型上添加then方法。

    Promise.prototype.then = function(onResolved, onRejected) {
        if(this.PromiseState === "fulfilled") {
            onResolved();
        }
        if(this.PromiseState === "rejected") {
            onRejected();
        }
    }
    
  6. executor的执行内容是异步的,应该等到异步执行后改变了状态才能执行then中的回调函数,异步执行前状态还是为pending

    let promise = new Promise((resolve, reject) => {
        setTimeout(()=> {
            resolve("OK");
        }, 1000);
    });
    
    function Promise(executor) {
        // ...
        this.callback = null;
    
        // 防止this指向window
        const self = this;
        function resolve(value) {
            if(self.PromiseState !== "pending") return;
            self.PromiseState = "fulfilled";
            self.PromiseResult = value;
            if(self.callback.onResolved) {
                self.callback.onResolved();
            }
        }
        
        function reject(reason) {
            if(self.PromiseState !== "pending") return;
            self.PromiseState = "rejected";
            self.PromiseResult = reason;
            if(self.callback.onRejected) {
                self.callback.onRejected();
            }
        }
        // ...
    }
    
    // then方法
    Promise.prototype.then = function(onResolved, onRejected) {
        // ...
        if(this.PromiseState === "pending") {
            // 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来
            this.callback = {
                onResolved,
                onRejected
            };
        }
    }
    
  7. 当一个Promise实例执行了多个then方法时,两个then里的方法都会执行。

    let promise = new Promise((resolve, reject) => {
        resolve("OK");
    });
    
    promise.then(value => {
        console.log("success");
    }, error => {
        console.log("fail");
    });
    
    promise.then(value => {
        console.log("success2");
    }, error => {
        console.log("fail2");
    });
    // success success2
    
    function Promise(executor) {
        // ...
        this.callback = null;
    
        // 防止this指向window
        const self = this;
        function resolve(value) {
            if(self.PromiseState !== "pending") return;
            self.PromiseState = "fulfilled";
            self.PromiseResult = value;
            self.callbacks.forEach(item => {
                item.onResolved();
            });
        }
        
        function reject(reason) {
            if(self.PromiseState !== "pending") return;
            self.PromiseState = "rejected";
            self.PromiseResult = reason;
            self.callbacks.forEach(item => {
                item.onRejected();
            });
        }
        // ...
    }
    
    // then方法
    Promise.prototype.then = function(onResolved, onRejected) {
        // ...
        if(this.PromiseState === "pending") {
            // 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来
            this.callbacks.push({
                onResolved,
                onRejected
            });
        }
    }
    
  8. then方法返回的也是一个Promise实例,这个实例的状态由执行的回调函数的结果来决定,如果回调函数的执行内容是非Promise实例,则都为成功状态;如果是Promise实例,状态根据这个实例的状态来定。

    • executor执行内容为同步时:

      Promise.prototype.then = function(onResolved, onRejected) {
          const self = this;
          return new Promise((resolve, reject) => {
              if(self.PromiseState === "fulfilled") {
                  // 拿到回调函数的返回值
                  // Promise实例:根据其结果状态决定then执行后该实例的状态;非Promise实例:状态都为成功
                  const result = onResolved(self.PromiseResult);
                  if(result instanceof Promise) {
                      // 既然是一个Promise实例,就能根据该实例的执行内容确定状态
                      result.then(v => {
                          resolve(v);
                      }, r => {
                          reject(r);
                      });
                  } else {
                      resolve(result);
                  }
              }
              if(self.PromiseState === "rejected") {
                  // 同上
                  const result = onRejected(self.PromiseResult);
                  if(result instanceof Promise) {
                      result.then(v => {
                          resolve(v);
                      }, r => {
                          reject(r);
                      });
                  } else {
                      resolve(result);
                  }
              }
              }
              // ...
          })
      }
      
    • executor执行内容为异步时:

      Promise.prototype.then = function(onResolved, onRejected) {
          const self = this;
          return new Promise((resolve, reject) => {
              // ...
              if(self.PromiseState === "pending") {
                  // 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来
                  self.callbacks.push({
                      onResolved: function() {
                          // 同上
                          const result = onResolved(self.PromiseResult);
                          if(result instanceof Promise) {
                              result.then(v => {
                                  resolve(v);
                              }, r => {
                                  reject(r);
                              });
                          } else {
                              resolve(result);
                          }
                      },
                      onRejected: function() {
                          // 同上
                          const result = onRejected(self.PromiseResult);
                          if(result instanceof Promise) {
                              result.then(v => {
                                  resolve(v);
                              }, r => {
                                  reject(r);
                              });
                          } else {
                              resolve(result);
                          }
                      }
                  });
              }
          })
      }
      
  9. 封装then方法中出现的重复代码,并处理

    Promise.prototype.then = function(onResolved, onRejected) {
        const self = this;
        return new Promise((resolve, reject) => {
            // 封装函数:根据结果改变状态
            function callback(fn) {
                try {
                    // 拿到回调函数的返回值
                    // Promise实例:根据其结果状态决定then执行后该实例的状态;非Promise实例:状态都为成功
                    let result = fn(self.PromiseResult);
                    if(result instanceof Promise) {
                        // 既然是一个Promise实例,就能根据该实例的执行内容确定状态
                        result.then(v => {
                            resolve(v);
                        }, r => {
                            reject(r);
                        });
                    } else {
                        resolve(result);
                    }
                } catch (error) {
                    reject(error);
                }
            }
    
            if(self.PromiseState === "fulfilled") {
                callback(onResolved);
            }
            if(self.PromiseState === "rejected") {
                callback(onRejected);
            }
            if(self.PromiseState === "pending") {
                // 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来
                self.callbacks.push({
                    onResolved: function() {
                        callback(onResolved);
                    },
                    onRejected: function() {
                        callback(onRejected);
                    }
                });
            }
        })
    }
    
  10. 添加catch方法并实现异常穿透,同时实现then只传递一个参数和不传递参数的情况。

    // 使用
    promise.then(value => {
        return new Promise((resolve, reject) => {
            reject("111 error")
        })
    }).then((value) => {
        console.log(222)
    }).catch(err => {
        console.log("err-------------")
        console.log(err)
    });
    
    // then方法
    Promise.prototype.then = function(onResolved, onRejected) {
        const self = this;
        // 不传第二个函数时,默认函数为一个抛出异常操作
        if(typeof onRejected !== "function") {
            onRejected = reason => {
                throw reason;
            }
        }
        // 不传第一个函数时,默认将实例结果值返回,可以实现成功时的值传递
        if(typeof onResolved !== "function") {
            onResolved = value => value;
        }
    
        return new Promise((resolve, reject) => {
            // ...
        })
    }
    
    // catch方法
    Promise.prototype.catch = function(onRejected) {
        return this.then(undefined, onRejected);
    }
    
  11. 添加Promise.resolvePromisereject方法。

    // resolve方法:根据传入参数的类型决定结果的状态
    Promise.resolve = function(value) {
        return new Promise((resolve, reject) => {
            if(value instanceof Promise) {
                // 既然是一个Promise实例,就能根据该实例的执行内容确定状态
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                });
            } else {
                resolve(value);
            }
        })
    }
    
    // reject方法:无论传入的参数是什么类型,结果都是失败状态
    Promise.reject = function(reason) {
        return new Promise((resolve, reject) => {
            reject(reason);
        })
    }
    
  12. 添加Promise.all方法:所有实例都成功则为成功,结果值为所有实例结果值组成的数组;有一个失败,则为失败,结果值为失败的实例的结果值。

    Promise.all = function(promises) {
        return new Promise((resolve, reject) => {
            let count = 0,
                resultArr = [];
            promises.forEach((item, index) => {
                item.then(v => {
                    count++;
                    // 按实例的索引值存储其对应结果
                    resultArr[index] = item.PromiseResult;
                    // 全部都为成功时为成功
                    if(count === promises.length) {
                        resolve(resultArr);
                    }
                }, r => {
                    reject(r);
                });
            });
        })
    }
    
  13. 添加Promise.race方法:实例中谁先改变状态,返回的状态和结果值就为该实例的状态和结果值。

    Promise.race = function(promises) {
        return new Promise((resolve, reject) => {
            promises.forEach(item => {
                item.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                });
            });
        })
    }
    
  14. then方法是一个异步任务。

    function Promise(executor) {
        // ...
    
        // 防止this指向window
        const self = this;
        function resolve(value) {
            // ...
            setTimeout(() => {
                self.callbacks.forEach(item => {
                    item.onResolved();
                });
            });
        }
        
        function reject(reason) {
            // ...
            setTimeout(() => {
                self.callbacks.forEach(item => {
                    item.onRejected();
                });
            });
        }
        // 参数为一个函数且立即执行,该函数需要两个函数参数改变promise的状态和结果值;抛出异常时状态为失败
        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }
    
    // then方法
    Promise.prototype.then = function(onResolved, onRejected) {
        // ...
    
        return new Promise((resolve, reject) => {
            // ...
            
            if(self.PromiseState === "fulfilled") {
                setTimeout(() => {
                    callback(onResolved);
                });
            }
            if(self.PromiseState === "rejected") {
                setTimeout(() => {
                    callback(onRejected);
                });
            }
            // ...
        })
    }
    

调整一下代码结构,整个promise.js源码如下:

function Promise(executor) {
    this.PromiseState = "pending";
    this.PromiseResult = null;
    this.callbacks = [];

    // 防止this指向window
    const self = this;
    function resolve(value) {
        if(self.PromiseState !== "pending") return;
        self.PromiseState = "fulfilled";
        self.PromiseResult = value;
        setTimeout(() => {
            self.callbacks.forEach(item => {
                item.onResolved();
            });
        });
    }
    
    function reject(reason) {
        if(self.PromiseState !== "pending") return;
        self.PromiseState = "rejected";
        self.PromiseResult = reason;
        setTimeout(() => {
            self.callbacks.forEach(item => {
                item.onRejected();
            });
        });
    }
    // 参数为一个函数且立即执行,该函数需要两个函数参数改变promise的状态和结果值;抛出异常时状态为失败
    try {
        executor(resolve, reject);
    } catch (error) {
        reject(error);
    }
}

// then方法
Promise.prototype.then = function(onResolved, onRejected) {
    // 不传第一个函数时,默认将实例结果值返回,可以实现成功时的值传递
    if(typeof onResolved !== "function") {
        onResolved = value => value;
    }
    // 不传第二个函数时,默认函数为一个抛出异常操作
    if(typeof onRejected !== "function") {
        onRejected = reason => {
            throw reason;
        }
    }

    const self = this;
    return new Promise((resolve, reject) => {
        // 封装函数:根据结果改变状态
        function callback(fn) {
            try {
                // 拿到回调函数的返回值
                // Promise实例:根据其结果状态决定then执行后该实例的状态;非Promise实例:状态都为成功
                let result = fn(self.PromiseResult);
                if(result instanceof Promise) {
                    // 既然是一个Promise实例,就能根据该实例的执行内容确定状态
                    result.then(v => {
                        resolve(v);
                    }, r => {
                        reject(r);
                    });
                } else {
                    resolve(result);
                }
            } catch (error) {
                reject(error);
            }
        }

        if(self.PromiseState === "pending") {
            // 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来
            self.callbacks.push({
                onResolved: function() {
                    callback(onResolved);
                },
                onRejected: function() {
                    callback(onRejected);
                }
            });
        } else if(self.PromiseState === "fulfilled") {
            setTimeout(() => {
                callback(onResolved);
            });
        } else if(self.PromiseState === "rejected") {
            setTimeout(() => {
                callback(onRejected);
            });
        }
        
    })
}

// catch方法
Promise.prototype.catch = function(onRejected) {
    return this.then(undefined, onRejected);
}

// resolve方法:根据传入参数的类型决定结果的状态
Promise.resolve = function(value) {
    return new Promise((resolve, reject) => {
        if(value instanceof Promise) {
            // 既然是一个Promise实例,就能根据该实例的执行内容确定状态
            value.then(v => {
                resolve(v);
            }, r => {
                reject(r);
            });
        } else {
            resolve(value);
        }
    })
}

// reject方法:无论传入的参数是什么类型,结果都是失败状态
Promise.reject = function(reason) {
    return new Promise((resolve, reject) => {
        reject(reason);
    })
}

// all方法
Promise.all = function(promises) {
    return new Promise((resolve, reject) => {
        let count = 0,
            resultArr = [];
        promises.forEach((item, index) => {
            item.then(v => {
                count++;
                // 按实例的索引值存储其对应结果
                resultArr[index] = item.PromiseResult;
                // 全部都为成功时为成功
                if(count === promises.length) {
                    resolve(resultArr);
                }
            }, r => {
                reject(r);
            });
        });
    })
}

// race方法
Promise.race = function(promises) {
    return new Promise((resolve, reject) => {
        promises.forEach(item => {
            item.then(v => {
                resolve(v);
            }, r => {
                reject(r);
            });
        });
    })
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

烤鱼界头牌半天妖发文致歉,背后暴露了哪些问题?

3月24日,半天妖烤鱼官方针对“两家门店食品安全问题”,发表致歉声明,并宣布将两家涉事门店永久关停。半天妖烤鱼爆出的食品安全问题再次提醒我们,加强门店监管和管理工作,保障消费者的健康和安全,成为了行业…

7.避免不必要的渲染

目录 1 组件更新机制 2 虚拟DOM配合Diff算法 3 减轻state 4 shouldComponentUpdate() 4.1 基本使用 4.2 使用参数 5 纯组件 5.1 基本使用 5.2 纯组件的比较方法 shallow compere 1 组件更新机制 当父组件重新渲染时,父组件的所有子组件也会重新…

如何理解AQS

AQS核心数据结构 AQS内部主要维护了一个FIFO(先进先出)的双向链表。 AQS数据结构原理 AQS内部维护的双向链表中的各个节点分别指向直接的前驱节点和直接的后续节点。所以,在AQS内部维护的双向链表可以从其中的任意一个节点遍历前驱结点和后…

【尝鲜版】ChatGPT插件开发指南

3月23日,OpenAI官方发布了一则公告,宣告ChatGPT已经支持了插件功能,现在处于内测阶段。插件的意义不仅仅在于功能的扩展,它直接让ChatGTP拥有了联网的能力!简直是猛兽出笼、蛟龙出海,要让ChatGPT大杀特杀啊…

phpstorm断点调试

环境:win10phpstorm2022phpstudy8lnmp 1、phpinfo(); 查看是否安装xdebug,没有走以下流程 2、phpstudy中切换不同版本php版本,有些版本不支持xdebug(如php8.0.2),有些已经自带了(如php7.3.9&a…

Java奠基】Java经典案例讲解

目录 卖飞机票 找质数 开发验证码 数组元素的复制 评委打分 数字加密 数字解密 抢红包 模拟双色球 二维数组 卖飞机票 需求:机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。按照如下规则计算机票价格: 旺季&…

技术分享——Java8新特性

技术分享——Java8新特性1.背景2. 新特性主要内容3. Lambda表达式4. 四大内置核心函数式接口4.1 Consumer<T>消费型接口4.2 Supplier<T>供给型接口4.3 Function<T,R>函数型接口4.4 Predicate<T> 断定型接口5. Stream流操作5.1 什么是流以及流的类型5.2…

[攻城狮计划]如何优雅的在RA2E1上运行RT_Thread

文章目录[攻城狮计划]|如何优雅的在RA2E1上运行RT_Thread准备阶段&#x1f697;开发板&#x1f697;开发环境&#x1f697;下载BSP&#x1f697;编译烧录连接串口总结[攻城狮计划]|如何优雅的在RA2E1上运行RT_Thread &#x1f680;&#x1f680;开启攻城狮的成长之旅&#xff0…

【ChatGPT】教你搭建多任务模型

ChatGPT教你搭建多任务模型 You: tell me what’s your version of gpt ? ChatGPT: As an AI language model developed by OpenAI, I am based on the GPT (Generative Pretrained Transformer) architecture. However, my version is known as GPT-3.5, which is an updat…

数据泄漏防护 (DLP) 工具保护敏感数据

通过实时安全监控&#xff0c;通过端点&#xff08;即 USB、电子邮件、打印等&#xff09;检测、中断和防止敏感数据泄露。使用 DataSecurity Plus 的数据泄漏防护 &#xff08;DLP&#xff09; 工具保护敏感数据不被泄露或被盗。DataSecurity Plus 主要功能包括&#xff1a; …

Android APP检查设备是否为平板

正文 Android APP判断设备是否为平板的三种方法&#xff1a; 通过屏幕尺寸判断。一般来说&#xff0c;平板电脑的屏幕尺寸比手机大很多&#xff0c;可以根据屏幕的长宽比和尺寸等信息来区分设备类型。通过屏幕像素密度判断。一般来说&#xff0c;平板电脑的屏幕像素密度比手机…

Java开发一年不到,来面试居然敢开口要20K,面完连8K都不想给~

前言 我的好朋友兼大学同学老伍家庭经济情况不错&#xff0c;毕业之后没两年自己存了点钱加上家里的支持&#xff0c;自己在杭州开了一家网络公司。由于公司不是很大所以公司大部分的开发人员都是自己面试的&#xff0c;近期公司发展的不错&#xff0c;打算扩招也面试了不少人…

四级数据库工程师 刷真题错题整理(三)数据库原理

1.数据模型是对现实世界进行抽象的工具&#xff0c;它按算机系统的观点模于提数据库系统中信息表示和操作手段的形式框架&#xff0c;主要用于 DBMS 的实现&#xff0c;是数据库系统的核心和基础。其中&#xff0c;数据操作是对数据间的动态行为。 2.数据库的型是稳定的&#…

day38_JDBC

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、数据库连接池 二、反射 三、封装DBUtil 零、 复习昨日 SQL注入 预处理语句 String sql "select * from user where id ?"; PreparedStat…

企业微信中如何拉黑?拉黑个人和群成员有什么区别?

企业微信既可以拉黑个人好友&#xff0c;又可以拉黑群好友。 1. 拉黑个人好友 拉黑好友通俗来说就是不想再接收到对方的信息&#xff0c;企业微信可以通过设置消息免打扰的方式来屏蔽对方的消息。 【客户聊天界面】-【右上角的小人标志】-【第一栏名称进入】-【右上角三点】…

C语言——动态内存管理 malloc、calloc、realloc、free的使用

目录 一、为什么存在动态内存分配 二、动态内存函数的介绍 2.1malloc和free 2.2calloc 2.3realloc 三、常见的动态内存错误 3.1对NULL指针的解引用操作 3.2对动态开辟空间的越界访问 3.3对非动态开辟的内存使用free释放 3.4使用free释放一块动态开辟内存的一部分 3.5…

奇安信_防火墙部署_透明桥模式

奇安信_防火墙部署_透明桥模式一、预备知识二、项目场景三、拓扑图四、基本部署配置1. 登录web控制台2.连通性配置3.可信主机配置4.授权导入5.特征库升级6.安全配置文件五、透明桥配置1. 创建桥2. 端口绑定桥3. 创建桥端口六、结语一、预备知识 安全设备接入网络部署方式 二、…

运算放大器:电压比较器

目录一、单限电压比较器二、滞回电压比较器三、窗口电压比较器最近在学习电机控制&#xff0c;遇到了与运算放大电路相关的知识&#xff0c;然而太久没有接触模拟电路&#xff0c;对该知识已经淡忘了&#xff0c;及时温故而知新&#xff0c;做好笔记&#xff0c;若有错误、不足…

字节跳动测试岗面试记:二面被按地上血虐,所幸Offer已到手...

在互联网做了几年之后&#xff0c;去大厂“镀镀金”是大部分人的首选。大厂不仅待遇高、福利好&#xff0c;更重要的是&#xff0c;它是对你专业能力的背书&#xff0c;大厂工作背景多少会给你的简历增加几分竞争力。 但说实话&#xff0c;想进大厂还真没那么容易。最近面试字…

3分钟阐述这些年我的 接口自动化测试 职业生涯经验分享

接口自动化测试学习教程地址&#xff1a;https://www.bilibili.com/video/BV1914y1F7Bv/ 你好&#xff0c;我是凡哥。 很高兴能够分享我的接口自动化测试经验和心得体会。在我目前的职业生涯中&#xff0c;接口自动化测试是我经常进行的一项任务。通过不断地学习和实践&#xf…
最新文章