• 手写Promise


    参考博客:
    1.zhangpaopao0609
    2.齐小神
    视频推荐

    为什么要有Promise?

    为了解决回调地狱问题,也就是函数嵌套函数的问题。例子:
    在这里插入图片描述

    Promise的实现

    Promise 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。
    Promise是基于Promises/A+规范实现的,可以通过此规范的步骤自己手动实现一个Promise

    功能简述

    1. Promise是一个构造函数,new Promise 时传入一个执行函数,并且执行函数是立即执行的
    2. 执行函数接收两个参数 resolve 函数 和 reject 函数,并且均能够接收参数
    3. Promise 的实例上有一个 then 方法, then 方法接收两个参数
    4. 进一步的,promise 有三个状态待定(pending),兑现(fulfilled),拒绝(rejected)。只能从pending到rejected, 或者从pending到fulfilled,状态一旦确认,就不会再改变。通过当前状态判断是否执行成功
    5. 然后就是解决传入promise是异步的问题
    6. 解决.then的链式调用,值的穿透

    具体实现代码

    const PENDING = 'PENDING';
    const FULFILLED = 'FULFILLED';
    const REJECTED = 'REJECTED';
    
    const resolvePromise = (promise2, x, resolve, reject) => {
      // 自己等待自己完成是错误的实现,用一个类型错误,结束掉 promise  Promise/A+ 2.3.1
      if (promise2 === x) { 
        return reject(new TypeError('Chaining cycle detected for promise #'))
      }
      // Promise/A+ 2.3.3.3.3 只能调用一次
      let called;
      // 后续的条件要严格判断 保证代码能和别的库一起使用
      if ((typeof x === 'object' && x != null) || typeof x === 'function') { 
        try {
          // 为了判断 resolve 过的就不用再 reject 了(比如 reject 和 resolve 同时调用的时候)  Promise/A+ 2.3.3.1
          let then = x.then;
          if (typeof then === 'function') { 
            // 不要写成 x.then,直接 then.call 就可以了 因为 x.then 会再次取值,Object.defineProperty  Promise/A+ 2.3.3.3
            then.call(x, y => { // 根据 promise 的状态决定是成功还是失败
              if (called) return;
              called = true;
              // 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1
              resolvePromise(promise2, y, resolve, reject); 
            }, r => {
              // 只要失败就失败 Promise/A+ 2.3.3.3.2
              if (called) return;
              called = true;
              reject(r);
            });
          } else {
            // 如果 x.then 是个普通值就直接返回 resolve 作为结果  Promise/A+ 2.3.3.4
            resolve(x);
          }
        } catch (e) {
          // Promise/A+ 2.3.3.2
          if (called) return;
          called = true;
          reject(e)
        }
      } else {
        // 如果 x 是个普通值就直接返回 resolve 作为结果  Promise/A+ 2.3.4  
        resolve(x)
      }
    }
    
    class Promise {
      constructor(executor) {
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks= [];
    
        let resolve = (value) => {
          if(this.status ===  PENDING) {
            this.status = FULFILLED;
            this.value = value;
            this.onResolvedCallbacks.forEach(fn=>fn());
          }
        } 
    
        let reject = (reason) => {
          if(this.status ===  PENDING) {
            this.status = REJECTED;
            this.reason = reason;
            this.onRejectedCallbacks.forEach(fn=>fn());
          }
        }
    
        try {
          executor(resolve,reject)
        } catch (error) {
          reject(error)
        }
      }
    
      then(onFulfilled, onRejected) {
        //解决 onFufilled,onRejected 没有传值的问题
        //Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
        //因为错误的值要让后面访问到,所以这里也要跑出个错误,不然会在之后 then 的 resolve 中捕获
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
        // 每次调用 then 都返回一个新的 promise  Promise/A+ 2.2.7
        let promise2 = new Promise((resolve, reject) => {
          if (this.status === FULFILLED) {
            //Promise/A+ 2.2.2
            //Promise/A+ 2.2.4 --- setTimeout
            setTimeout(() => {
              try {
                //Promise/A+ 2.2.7.1
                let x = onFulfilled(this.value);
                // x可能是一个proimise
                resolvePromise(promise2, x, resolve, reject);
              } catch (e) {
                //Promise/A+ 2.2.7.2
                reject(e)
              }
            }, 0);
          }
    
          if (this.status === REJECTED) {
            //Promise/A+ 2.2.3
            setTimeout(() => {
              try {
                let x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              } catch (e) {
                reject(e)
              }
            }, 0);
          }
    
          if (this.status === PENDING) {
            this.onResolvedCallbacks.push(() => {
              setTimeout(() => {
                try {
                  let x = onFulfilled(this.value);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                  reject(e)
                }
              }, 0);
            });
    
            this.onRejectedCallbacks.push(()=> {
              setTimeout(() => {
                try {
                  let x = onRejected(this.reason);
                  resolvePromise(promise2, x, resolve, reject)
                } catch (e) {
                  reject(e)
                }
              }, 0);
            });
          }
        });
    
        return promise2;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140

    常用的Promise静态方法

    Promise.all()全部子实例都成功才算成功,有一个子实例失败就算失败

    function _all (promises) {
      /*
      * count 计数器,与len比较,判断是否所有的promise都已经成功了
      * result 用于存放成功的结果
      */
      let count=0,len=promises.length, result=[];
      return new Promise((resolve, reject) => {
        // 依次判断传入的promise实例是否成功
        for(let p of promises) {
          Promise.resolve(p).then(res => {
            result[count] = res;
            count++;
            if(count === len) {
              //相等,说明所有的promise实例都成功了, 才可以resolve结果
              resolve(result);
            }
          }).catch(err => 
          //只要有一个失败了就reject出去
          reject(err));
        }
      })
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    Promise.any()有一个子实例成功就算成功,全部子实例失败才算失败

    function _any (promises) {
      let result =[],len=promises.length, count=0;
      return new Promise((resolve, reject) => {
        for(let p of promises) {
          Promise.resolve(p).then(res => {
            resolve(res);
          }).catch(err => {
            result[count]=err;
            count++;
            if(count===len){
              reject(result)
            }
          })
        }
      })
    } 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Promise.race()用来处理多个请求,采用最快的(谁先完成用谁的)

    function _race (promises) {
      return new Promise((resolve, reject) => {
        for(p of promises) {
          Promise.resolve(p).then(res => {
            resolve(res)
          }).catch(err=> reject(err))
        }
      })
    } 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Promise.allSettled()返回每个Promised的结果数组,即fulfilled或rejecte

    function _allSettled (promises) {
      let result=[],len=promises.length; count=0;
      return new Promise((resolve, reject) => {
        for(let p of promises) {
          Promise.resolve(p).then(res => {
            result[count] ={
              status:'fulfilled',
              result:res
            }
            count++;
            if(count === len) {
              resolve(result)
            }
          }).catch(err => {
            result[count] ={
              status:'rejected',
              result:err
            }
            count++;
            if(count === len) {
              reject(result);
            }
          })
        }
      })
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 相关阅读:
    Angular 中的路由
    C++动态内存管理
    Netty之DefaultAttributeMap与AttributeKey的机制和原理
    FPGA 多路视频处理:图像缩放+视频拼接显示,HDMI采集,提供2套工程源码和技术支持
    边缘计算技术的崭新篇章:赋能未来智能系统
    【Flask】Flask启程与实现一个基于Flask的最小应用程序
    Transactional的7种Propagation 事务配置 开启 关闭 spring springboot mybatis
    《用Go语言自制解释器》之第3章 求值
    springboot系列(二十四):如何实现Excel文件导出?这你得会 | 超级详细,建议收藏
    谷粒商城10——分布式缓存Redis 分布式锁Redisson SpringCache自定义缓存配置
  • 原文地址:https://blog.csdn.net/qq_43178432/article/details/126431770