调用Promise

  1. //#region 测试then方法
  2. let p = new Promise((resolve, reject) => {
  3. // setTimeout(() => {
  4. // // resolve('ok')
  5. // reject('no')
  6. // }, 1000);
  7. // resolve('ok')
  8. reject('no~')
  9. // throw 'Error'
  10. });
  11. p.then(v => {
  12. console.log(v)
  13. }, r => {
  14. console.log(r)
  15. })
  16. //#endregion
  17. //#region 测试Promise对象返回结果
  18. // let p = new Promise((resolve, reject) => {
  19. // // setTimeout(() => {
  20. // // // resolve('ok')
  21. // // reject('no')
  22. // // }, 1000);
  23. // // resolve('ok')
  24. // reject('no~')
  25. // // throw 'Error'
  26. // });
  27. // console.log(p);
  28. //#endregion
  29. //#region 测试then方法返回对象
  30. // const res = p.then(value => {
  31. // // console.log(value);
  32. // // return '213'
  33. // // throw 'ERROR'
  34. // return new Promise((resolve, reject) => {
  35. // resolve('888')
  36. // })
  37. // }, reason => {
  38. // // return '213'
  39. // // return new Promise((resolve, reject) => {
  40. // // reject('888')
  41. // // })
  42. // // console.log(reason);
  43. // })
  44. // console.log(res);
  45. //#endregion
  46. //#region 测试catch
  47. // p.then(value => {
  48. // console.log(111);
  49. // })
  50. // .then(value => {
  51. // console.log(222);
  52. // })
  53. // .then(value => {
  54. // console.log(333);
  55. // })
  56. // .catch(reason => {
  57. // console.log(reason);
  58. // })
  59. //#endregion
  60. //#region 测试resolve & reject
  61. // let p1 = Promise.resolve('ok');
  62. // const p2 = Promise.resolve(new Promise((resolve, reject) => {
  63. // // resolve('Success');
  64. // reject("error");
  65. // }));
  66. // const p3 = Promise.resolve(Promise.resolve('Oh Yeah'));
  67. // console.log(p1);
  68. // console.log(p2);
  69. // console.log(p3);
  70. // let p4 = Promise.reject('no');
  71. // let p5 = Promise.reject(new Promise((resoleve, reject) => {
  72. // reject('no for Promise')
  73. // }));
  74. // let p6 = Promise.reject(Promise.resolve('ok'))
  75. // let p7 = Promise.reject(Promise.reject('no~'))
  76. // console.log(p4);
  77. // console.log(p5);
  78. // console.log(p6);
  79. // console.log(p7);
  80. //#endregion
  81. //#region 测试all方法
  82. // let p1 = new Promise((resolve, reject) => {
  83. // resolve('ok1')
  84. // });
  85. // let p2 = new Promise((resolve, reject) => {
  86. // reject('ok2')
  87. // });
  88. // let p3 = new Promise((resolve, reject) => {
  89. // resolve('ok3')
  90. // });
  91. // let res = Promise.all([p1, p2, p3]);
  92. // console.log(res);
  93. //#endregion
  94. //#region 测试race方法
  95. // let p1 = new Promise((resolve, reject) => {
  96. // setTimeout(function () {
  97. // resolve('ok1')
  98. // })
  99. // })
  100. // let p2 = Promise.reject('ok2')
  101. // let p3 = Promise.resolve('ok3')
  102. // let res = Promise.race([p1, p2, p3])
  103. // console.log(res);
  104. //#endregion
  105. //#region 测试then函数异步回调
  106. // let p1 = new Promise((resolve, reject) => {
  107. // resolve('OK');
  108. // console.log(111);
  109. // });
  110. // p1.then(value => {
  111. // console.log(222);
  112. // });
  113. // console.log(333);
  114. // //111 333 222
  115. //#endregion

定义Promise

定义过程中的注意点

传进来的是Promise 为什么要.then呢? 因为这样才能拿到该Promise对象返回的结果,再交给resolve或reject去执行,否则抛过去一个Promise对象,PromiseResult 结果就是给Promise对象的返回值

定义思路

  1. 初始结构搭建
  2. resolve与reject结构搭建
  3. resolve与reject函数实现
  4. throw抛出错误改变状态

    1. try {
    2. executor(resolve, reject)
    3. } catch (error) {
    4. reject(error)
    5. }
  5. 状态只能修改一次 if (this.PromiseState !== 'pending') return;

  6. then方法执行回调
  7. 异步任务then方法执行回调

    1. if (this.PromiseState === 'pending') {
    2. this.callbacks.push({
    3. onResolve() {
    4. callback(onResolved)
    5. },
    6. onRejected() {
    7. callback(onRejected)
    8. }
    9. })
    10. }
  8. 指定多个回调

    1. this.callbacks.forEach(item => {
    2. item.onResolve(data)
    3. })
  9. 同步修改状态then方法返回结果 callback(onResolve)

  10. 异步修改状态then方法返回结果 onResolve() { callback(onResolved) }
  11. catch方法与异常穿透 this.then(undefined, onRejected)
  12. Promise.resolve
  13. Promise.reject reject(reason)
  14. Promise.all方法实现 if (count === promises.length) { resolve(arr) }
  15. Promise.race方法实现
  16. then回调函数异步执行的实现 onResolve() { callback(onResolved) }

    普通构造函数

    ```javascript function Promise(executor) {

    // 添加属性 this.PromiseState = ‘pending’; //返回的状态 this.PromiseResult = null; //返回的结果 this.callbacks = [];

    const self = this;

    //resolve 函数 function resolve(data) { //连续调用resolve|reject时状态只能修改一次 if (self.PromiseState !== ‘pending’) return; //1. 修改对象的状态 (promiseState)为成功 self.PromiseState = ‘fulfilled’; //2. 设置对象结果值 (promiseResult) self.PromiseResult = data;

    //变为异步微任务 queueMicrotask(() => { //异步调用时,执行then保存的onRejected方法 self.callbacks.forEach(item => {

    1. item.onResolved(data)

    }); }) }

    //reject 函数 function reject(data) { //连续调用resolve|reject时状态只能修改一次 if (self.PromiseState !== ‘pending’) return; //1. 修改对象的状态 (promiseState)为成功 self.PromiseState = ‘rejected’; //2. 设置对象结果值 (promiseResult) self.PromiseResult = data;

    //变为异步微任务 queueMicrotask(() => { //异步调用时,执行then保存的onRejected方法 self.callbacks.forEach(item => {

     item.onRejected(data);
    

    }); }) }

    try { //同步调用『执行器函数』 executor(resolve, reject); } catch (err) { reject(err) } }

//添加 then 方法 Promise.prototype.then = function (onResolved, onRejected) {

//判断回调函数参数 //如果用户没有定义onRejected,那么在reject中就会报错,所有给添加一个默认函数 //该函数抛出异常,以此达到一出错可以一直往后抛(下一个接收上一个的异常) 直到抛到catch实现穿透 if (typeof onRejected !== ‘function’) { //因为这里本来就是出错的回调 所以可以直接抛错 onRejected = reason => { throw reason } } //当用户没指定成功回调时resolve会找不到而报错 if (typeof onResolved !== ‘function’) { onResolved = value => value }

/ then方法返回结果 一定是一个Promise对象,当then返回不同值时会响应返回不同的结果 [[PromiseState]]: “fulfilled” || “rejected”,[[PromiseResult]]: “执行返回的结果!” 1.Promise对象 状态为该对象返回的状态,返回值为对象的值 2.非Promise对象 状态为成功, 返回值为对象的成功的值 3.抛出错误 状态为失败, 返回值为对象的值 / / return中使用了 => this向外找到找 依然指向构造函数。 如果是普通函数,因为没有被谁调用所以指向window。 * 这里的return的就是一个新的构造函数( Promise) 与用户const p = new Promise该构造函数无关。 其中调用的resolve和reject也是, 其作用只是返回对应的状态和结果而已, 不会修改到p的结果 1.这里的Promise是自己定义的所以return的就是该构造函数, 也就是传入的这个参数(函数new Promise) new之后Promise函数会执行executor, 自然里边的代码也会被执行, 并返回初始结果(PromiseState: ‘pending’和PromiseResult:null)

2. 因为要返回不同的状态和结果, 所以可以在下方调用成功或失败回调时根据返回值修改状态和结果( 有executor所以下方函数会被执行一遍),
3.

*/ const self = this; return new Promise((resolve, reject) => {

//定义一个公用函数
function callback(type) {
  //当then返回的是抛出错误时,返回失败的状态和结果
  try {
    const result = type(self.PromiseResult);
    // 根据then的返回值修改对应的状态和结果
    if (result instanceof Promise) {
      //如果result是Promise(该对象是新new的),那它身上就有then方法,then方法接收resolve或reject的结果,
      //所以能根据result的执行结果拿到value或reason,并调用对应的方法修改状态和结果
      result.then(v => {
        resolve(v);
      }, r => {
        reject(r);
      })
    } else {
      //如果不是Promise 则返回成功状态和结果
      //原生Promise在失败回调中 then返回的也是返回成功状态
      //调用resolve修改状态和结果
      resolve(result)
    }
  } catch (error) {
    reject(error);
  }
}

//该回调p.then , this指向实例对象p
//调用成功回调
if (this.PromiseState === 'fulfilled') {
  //变为异步微任务
  queueMicrotask(() => {
    callback(onResolved);
  });
}
//调用失败回调
if (this.PromiseState === 'rejected') {
  //变为异步微任务
  queueMicrotask(() => {
    callback(onRejected);
  });
}

//如果是异步 则还来不及调用resolve或reject,所以要把调用then的方法交给resolve或reject
//待用户异步执行resolve或reject时让其调用
if (this.PromiseState === 'pending') {
  //保存这两个方法到构造函数上,用于给resolve或reject调用
  //不能保存到原型上,因为原型链上的属性是共享的,多个对象实例则会修改到
  //因为then是可以连续调用多个的 所以用数组循环指向
  this.callbacks.push({
    //异步原因本来直接将onResolved或onRejected交给resolve执行,但因为需要then返回状态和结果,
    //所以对then的回调函数进行修改,在修改的函数里也有执行了一遍onResolved或onRejected,所以没有问题

    //成功回调
    onResolved: function () {
      callback(onResolved)
    },
    //失败回调
    onRejected: function () {
      callback(onRejected)
    }
  })
}

}) }

//添加 catch 方法 // 原生Promise的catch方法: 如果指定了某一个失败回调则执行该回调, // 如果未指定了失败回调则一直往下穿透直到catch,这一功能在then方法中(throw reason)实现 Promise.prototype.catch = function (onRejected) { //catch方法是捕捉失败的方法,所以实例对象一定是返回reject, //所以调用then方法接收onRejected回调函数,不需要成功所以onReolve=undefined this.then(‘undefined’, onRejected) }

//添加 resolve 方法 Promise.resolve = function (value) { return new Promise((resolve, reject) => { if (value instanceof Promise) { value.then(v => { resolve(v) }, r => { reject(r) }) } else { resolve(value) } }) }

//添加 reject 方法 //原生reject //状态:一定是失败,不管传入是否为Promise对象 //结果:返回传入的结果,如果是Promise也返回Promise Promise.reject = function (reason) { return new Promise((resolve, reject) => { reject(reason) }) }

//添加 all 方法 Promise.all = function (promises) { //返回的结果是一个Promise对象 状态:根据情况 结果:[] || 报错 return new Promise((resolve, reject) => { //用于计算每个Promise是否执行成功 let count = 0; let arr = []; promises.forEach((item, index) => { //拿到的是一个个Promise对象 item.then(v => { //每个promise对象 都成功 count++; //将当前promise对象成功的结果 根据顺序存入到数组中 arr[index] = v; //都成功后才能执行resolve修改状态和结果,否则有错误的时候无法再调用 if (count === promises.length) { //将结果数组作为参数传出 resolve(arr) } }, r => { //有一个失败则可以直接修改状态为失败和结果:失败的结果 reject(r) }) }) }) }

//添加 race 方法 //谁先执行完,无论成功失败 Promise.race = function (promises) { return new Promise((resolve, reject) => { promises.forEach(item => { item.then(v => { //修改返回对象的状态为 『成功』 resolve(v) }, r => { //修改返回对象的状态为 『失败』 reject(r) }) }) }) }

<a name="nmpC8"></a>
### class定义
普通函数版本 可以看到this指向问题
```javascript
class Promise {
  constructor(executor) {
    // 添加属性
    this.PromiseState = 'pending'; //返回的状态
    this.PromiseResult = null; //返回的结果
    this.callbacks = [];

    const self = this;

    //resolve 函数
    function resolve(data) {
      if (self.PromiseState !== 'pending') return;
      //1. 修改对象的状态 (promiseState)为成功
      self.PromiseState = 'fulfilled';
      //2. 设置对象结果值 (promiseResult)
      self.PromiseResult = data;

      //变为异步微任务
      queueMicrotask(() => {
        //异步调用时,执行then保存的onRejected方法
        self.callbacks.forEach(item => {
          item.onResolved(data)
        });
      })
    }

    //reject 函数
    function reject(data) {
      if (self.PromiseState !== 'pending') return;
      //1. 修改对象的状态 (promiseState)为成功
      self.PromiseState = 'rejected';
      //2. 设置对象结果值 (promiseResult)
      self.PromiseResult = data;

      //变为异步微任务
      queueMicrotask(() => {
        //异步调用时,执行then保存的onRejected方法
        self.callbacks.forEach(item => {
          item.onRejected(data);
        });
      })
    }

    try {
      //同步调用『执行器函数』
      executor(resolve, reject);
    } catch (err) {
      reject(err)
    }
  }
  //添加 then 方法
  then(onResolved, onRejected) {
    //判断回调函数参数
    //如果用户没有定义onRejected,那么在reject中就会报错,所有给添加一个默认函数
    //该函数抛出异常,以此达到一出错可以一直往后抛(下一个接收上一个的异常) 直到抛到catch实现穿透
    if (typeof onRejected !== 'function') {
      //因为这里本来就是出错的回调 所以可以直接抛错
      onRejected = reason => {
        throw reason
      }
    }
    //当用户没指定成功回调时resolve会找不到而报错
    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }

    /* 
      then方法返回结果 一定是一个Promise对象,当then返回不同值时会响应返回不同的结果
      [[PromiseState]]: "fulfilled" || "rejected",[[PromiseResult]]: "执行返回的结果!"
      1.Promise对象 状态为该对象返回的状态,返回值为对象的值
      2.非Promise对象 状态为成功, 返回值为对象的成功的值
      3.抛出错误 状态为失败, 返回值为对象的值
    */
    /* 
      ** return中使用了 => this向外找到找 依然指向构造函数。 如果是普通函数,因为没有被谁调用所以指向window。**
      ** 这里的return的就是一个新的构造函数( Promise) 与用户const p = new Promise该构造函数无关。 
         其中调用的resolve和reject也是, 其作用只是返回对应的状态和结果而已, 不会修改到p的结果 **
      1.这里的Promise是自己定义的所以return的就是该构造函数, 也就是传入的这个参数(函数new Promise)
        new之后Promise函数会执行executor, 自然里边的代码也会被执行, 并返回初始结果(PromiseState: 'pending'和PromiseResult:null)
      2. 因为要返回不同的状态和结果, 所以可以在下方调用成功或失败回调时根据返回值修改状态和结果( 有executor所以下方函数会被执行一遍),
      3.
    */
    const self = this;
    return new Promise((resolve, reject) => {

      //定义一个公用函数
      function callback(type) {
        //当then返回的是抛出错误时,返回失败的状态和结果
        try {
          const result = type(self.PromiseResult);
          // 根据then的返回值修改对应的状态和结果
          if (result instanceof Promise) {
            //如果result是Promise(该对象是新new的),那它身上就有then方法,then方法接收resolve或reject的结果,
            //所以能根据result的执行结果拿到value或reason,并调用对应的方法修改状态和结果
            result.then(v => {
              resolve(v);
            }, r => {
              reject(r);
            })
          } else {
            //如果不是Promise 则返回成功状态和结果
            //原生Promise在失败回调中 then返回的也是返回成功状态
            //调用resolve修改状态和结果
            resolve(result)
          }
        } catch (error) {
          reject(error);
        }
      }

      //该回调p.then , this指向实例对象p
      //调用成功回调
      if (this.PromiseState === 'fulfilled') {
        //变为异步微任务
        queueMicrotask(() => {
          callback(onResolved);
        });
      }
      //调用失败回调
      if (this.PromiseState === 'rejected') {
        //变为异步微任务
        queueMicrotask(() => {
          callback(onRejected);
        });
      }

      //如果是异步 则还来不及调用resolve或reject,所以要把调用then的方法交给resolve或reject
      //待用户异步执行resolve或reject时让其调用
      if (this.PromiseState === 'pending') {
        //保存这两个方法到构造函数上,用于给resolve或reject调用
        //不能保存到原型上,因为原型链上的属性是共享的,多个对象实例则会修改到
        //因为then是可以连续调用多个的 所以用数组循环指向
        this.callbacks.push({
          //异步原因本来直接将onResolved或onRejected交给resolve执行,但因为需要then返回状态和结果,
          //所以对then的回调函数进行修改,在修改的函数里也有执行了一遍onResolved或onRejected,所以没有问题

          //成功回调
          onResolved: function () {
            callback(onResolved)
          },
          //失败回调
          onRejected: function () {
            callback(onRejected)
          }
        })
      }
    })
  }

  //添加 catch 方法
  // 原生Promise的catch方法: 如果指定了某一个失败回调则执行该回调,
  // 如果未指定了失败回调则一直往下穿透直到catch,这一功能在then方法中(throw reason)实现
  catch (onRejected) {
    //catch方法是捕捉失败的方法,所以实例对象一定是返回reject,
    //所以调用then方法接收onRejected回调函数,不需要成功所以onReolve=undefined
    this.then('undefined', onRejected)
  }
  /*********以下添加静态方法,不属于原型*********/
  //添加 resolve 方法
  static resolve(value) {
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      } else {
        resolve(value)
      }
    })
  }
  //添加 reject 方法
  //原生reject
  //状态:一定是失败,不管传入是否为Promise对象
  //结果:返回传入的结果,如果是Promise也返回Promise
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }
  //添加 all 方法
  static all(promises) {
    //返回的结果是一个Promise对象 状态:根据情况 结果:[] || 报错
    return new Promise((resolve, reject) => {
      //用于计算每个Promise是否执行成功
      let count = 0;
      let arr = [];
      promises.forEach((item, index) => {
        //拿到的是一个个Promise对象
        item.then(v => {
          //每个promise对象 都成功
          count++;
          //将当前promise对象成功的结果 根据顺序存入到数组中
          arr[index] = v;
          //都成功后才能执行resolve修改状态和结果,否则有错误的时候无法再调用
          if (count === promises.length) {
            //将结果数组作为参数传出
            resolve(arr)
          }
        }, r => {
          //有一个失败则可以直接修改状态为失败和结果:失败的结果
          reject(r)
        })
      })
    })
  }
  //添加 race 方法
  //谁先执行完,无论成功失败
  static race(promises) {
    return new Promise((resolve, reject) => {
      promises.forEach(item => {
        item.then(v => {
          //修改返回对象的状态为 『成功』
          resolve(v)
        }, r => {
          //修改返回对象的状态为 『失败』
          reject(r)
        })
      })
    })
  }
}

箭头函数版本 解决this指向问题

// es6 class + 箭头函数解决this指向问题
class Promise {
  constructor(executor) {
    this.PromiseState = 'pending';
    this.PromiseResult = null;
    this.callbacks = [];

    //箭头函数让this执行外层
    const resolve = (data) => {
      if (this.PromiseState !== 'pending') return;
      this.PromiseState = 'fulfilled';
      this.PromiseResult = data;

      queueMicrotask(() => {
        this.callbacks.forEach(item => {
          item.onResolved(data)
        })
      })
    }

    const reject = (data) => {
      if (this.PromiseState !== 'pending') return;
      this.PromiseState = 'rejected';
      this.PromiseResult = data;

      queueMicrotask(() => {
        this.callbacks.forEach(item => {
          item.onRejected(data)
        })
      })
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onResolved, onRejected) {
    if (typeof onRejected !== 'function') {
      onRejected = (reason) => {
        throw reason
      }
    }

    if (typeof onResolved !== 'function') {
        onResolved = value => value
    }

    return new Promise((resolve, reject) => {

      const callback = (type) => {
        try {
          const result = type(this.PromiseResult);
          if (result instanceof Promise) {
            result.then(v => {
              resolve(v)
            }, r => {
              reject(r)
            })
          } else {
            resolve(result)
          }
        } catch (error) {
          reject(error)
        }
      }

      if (this.PromiseState === 'fulfilled') {
        queueMicrotask(() => {
          callback(onResolved)
        })
      }

      if (this.PromiseState === 'rejected') {
        queueMicrotask(() => {
          callback(onRejected)
        })
      }

      if (this.PromiseState === 'pending') {
        this.callbacks.push({
          onResolved() {
            callback(onResolved)
          },
          onRejected() {
            callback(onRejected)
          }
        })
      }
    })
  }

  catch (onRejected) {
    this.then(undefined, onRejected)
  }

  static resolve(value) {
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      } else {
        resolve(value)
      }
    })
  }

  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

  static all(promises) {
    return new Promise((resolve, reject) => {
      let count = 0;
      let arr = [];

      promises.forEach((item, index) => {
        item.then(v => {
          count++;
          arr[index] = v;
          if (count === promises.length) {
            resolve(arr)
          }
        }, r => {
          reject(r)
        });
      })
    })
  }

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