zoukankan      html  css  js  c++  java
  • 手写promise第三天

    2020-09-24
    手写promise第三天
    静态方法all:
    • all作为promise中的一个静态方法 只能通过Promise.all调用
    • all接收一个数组作为参数 这个数组中的值可以是普通值 也可以是promise对象
    • all方法会等数组中所有promise执行完之后统一返回一个数组
    静态方法resolve:
    • resolve接收一个值作为参数 这个值可以是普通值也可以是promise对象
    • 如果是promise对象 那么直接返回
    • 如果是普通值 那么将普通值包裹在promise里再返回
    catch方法:
    • 在promise的then方法中 一旦出现错误 由于then的特性 这个错误会一直传递到最后
    • catch方法就是写在最后捕获这个错误的
    finally:
    • 无论promise最后是成功还是失败 值都会传到finally方法中去
    • finally接收一个回调函数作为参数 并返回一个新的promise 在新promise的then中
    • 可以拿到promise最后成功或失败的值
    • 如果callback的返回值是一个异步的promise
    • 那么then应该等异步的promise执行完才能执行
    const PENDING = 'pengding';
    const FULFILLED = 'fulfilled';
    const REJECTED = 'rejected';
    
    class MyPromise {
      status = PENDING; // 当前promise的状态
      value = undefined; // 当前promise的值
      reason = undefined; // 当前promise如果失败 失败的原因
      successCallbacks = []; // 如果异步 那么将回调存入到对应回调库中
      rejectCallbacks = [];
      // promise 的构造函数接受一个执行器 这个执行器会立即执行
      constructor(executor) {
        // 这个执行器接收两个参数 第一个参数是执行成功 第二个是失败
        // 在执行器执行的过程中如果resolve执行 那么这个promise成功
        try {
          executor(this.resolve, this.reject);
        } catch (error) {
          this.reject(error);
        }
      }
      // all方法接收一个数组作为参数
      // 例如['a', p1, p2, p3, 'b'] 其中p1p2p3是promise对象
      static all(array) {
        let count = 0;
        let results = []; // 声明一个结果数组 接收数组每一项的结果
        return new MyPromise((res, rej) => { // all方法返回一个新的promise对象
          function setData(index, value) { // 往results里面放值的函数
            count++; // 没放入一个值 处理过的数量加1
            results[index] = value; // results对应项设置好值
            if (count === array.length) { // 如果处理过值的总数已经等于array的长度 说明所有的值都处理完了 
              res(results); // 返回成功的结果
            }
          }
          for (let i = 0; i < array.length; i++) {
            if (array[i] instanceof MyPromise) { // 如果这一项是promise类型的
              array[i].then((val) => { // 那么等promise执行完 在then里面拿到执行结果再往results数组里放
                setData(i, val);
              }, reason => {
                rej(reason); // 如果有一项的promise出错了 直接rej
              });
            } else { // 如果是普通值 直接往数组里放
              setData(i, array[i]);
            }
          }
        })
      }
    
      // 静态resolve接收一个参数
      static resolve(value) {
        if (value instanceof MyPromise) return value; // 如果这个参数是promise对象 那么直接返回 
        return new MyPromise(resolve => resolve(value)); // 如果不是 用promise包裹后返回
      }
    
      // 成功调用resolve方法 接收一个参数作为这个promise的返回值存在promise对象中
      resolve = data => {
        // 一旦status状态不是pending 那么就不再执行 保证状态不可逆
        if (this.status !== PENDING) return;
        this.status = FULFILLED;
        this.value = data; // 将promise成功获得的数据存在value中
        // 判断成功回调函数库中是否用未执行的函数 有的话依次执行
        while (this.successCallbacks.length) {
          this.successCallbacks.shift()();
        }
      }
      // 同resolve
      reject = reason => {
        if (this.status !== PENDING) return;
        this.status = REJECTED;
        this.reason = reason;
        while (this.rejectCallbacks.length) this.rejectCallbacks.shift()();
      }
      // then方法 接收两个函数作为参数 第一个是成功的回调
      then = (successCallback, rejectCallback) => {
        successCallback = successCallback || (value => value);
        rejectCallback = rejectCallback || (reason => { throw reason });
        // then方法 返回的是一个新的promise对象 所以在执行then的时候 new一个新的promise
        // 同样的 这个新promise的执行器也会立即执行
        let promise2 = new MyPromise((resolve, reject) => {
          // 当执行到then方法时候 status已经是FULFILLED说明promise已经执行成功
          // 直接执行成功的回调 
          // 同时将成功回调的返回值传递给下一个promise的resolve方法
          setTimeout(() => {
            try {
              if (this.status === FULFILLED) {
                const thenReturnVal = successCallback(this.value);
                resolvePromise(promise2, thenReturnVal, resolve, reject);
              } else if (this.status === REJECTED) {
                const thenReturnVal = rejectCallback(this.reason);
                resolvePromise(promise2, thenReturnVal, resolve, reject);
              } else {
                this.successCallbacks.push(() => {
                  try {
                    const thenReturnVal = successCallback(this.value);
                    resolvePromise(promise2, thenReturnVal, resolve, reject);
                  } catch (error) {
                    reject(error);
                  }
                });
                this.rejectCallbacks.push(() => {
                  try {
                    const thenReturnVal = rejectCallback(this.reason);
                    resolvePromise(promise2, thenReturnVal, resolve, reject);
                  } catch (error) {
                    reject(error);
                  }
                })
              }
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
        return promise2;
      }
      finally = callback => {
        // finally 也返回一个新的promise 在这个新promise的then方法里可以拿到最后成功或失败的值
        return this.then(value => { // 利用then方法可以直到最后是成功了还是失败了 无论成功还是失败都要执行callback
          // 如果callback的返回值是一个异步的promise 利用resolve静态方法包裹这个返回值
          // 例如 如果callback回调返回了 p3 而p3是一个延迟2秒执行的promise
          // 那么MyPromise.resolve(p3) === p3 也就是 p3.then。。。这样finally就会等这个promise执行完 才会调用then方法
          return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
          // 同样的 如果callback的promise是失败的 那么执行抛出这个reason
          return MyPromise.resolve(callback()).then(() => { throw reason });
        }); // 调用then方法获取当前promise的状态
      }
      // promise中一旦某一处有错误发生 会因为then的特性一直传递下去 直到最后这个catch里
      catch = rejectCallback => {
        return this.then(undefined, rejectCallback);
      }
    }
    
    function resolvePromise(promise2, x, resolve, reject) {
      if (promise2 === x) {
        reject(new TypeError('重复调用自己了哦~'));
      }
      if (x instanceof MyPromise) {
        // 是promise对象 那需要调用Promise的then方法判断这个promise是否成功
        // 如果成功 调用resolve方法 并且把值传递下去 如果失败 调用reject并且把原因传递下去
        x.then(value => resolve(value), reason => reject(reason));
        // x.then(resolve, reject);
      } else {
        resolve(x);
      }
    }
    
    const p1 = new MyPromise((resolve, reject) => {
      resolve('p1 complete');
    })
    
    const p2 = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        resolve('p2 complete');
      }, 1000);
    })
    const p3 = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        resolve('p3 complete');
      }, 2000);
    })
    
    // let all = MyPromise.all(['a', p1, p2, p3, 'b']);
    
    // all.then(value => {
    //   console.log(value);
    // }, reason => {
    //   console.log(reason);
    // })
    
    // MyPromise.resolve(100).then(value => console.log(value));
    // MyPromise.resolve(p2).then(value => console.log(value));
    
    // p1.finally(() => {
    //   console.log('finally');
    //   return p3;
    // }).then(val => console.log(val), reason => console.warn(reason));
    
    p1
      .then(() => {
        console.log(66666)
        throw new Error('error');
      })
      .then(value => console.log(value))
      .catch(reason => {
        console.log(reason);
      });
    总结:
    • 还还还还没还还有还还处理then中的异步问题
    • finally和then还是有些混乱...
    • 在调用到reject的情况有两种 一是then中成功回调报错 二是直接调用reject方法
  • 相关阅读:
    Mysql语句练习
    Mysql-------查询各科成绩前三名的记录
    Mysql--查询"01"课程比"02"课程成绩高的学生的信息及课程分数
    模态框拖拽案例分析--元素偏移量 offset 系列
    CSS中z-index的属性与使用
    《将博客搬至CSDN》
    CSS中Position几种属性的总结
    考研数学一
    ubuntu16.04安装mysql报错解决
    LoRaWAN 规范1.0 (章节10~13)
  • 原文地址:https://www.cnblogs.com/lanpang9661/p/13726883.html
Copyright © 2011-2022 走看看