手写promise原理

68 阅读1分钟
  1. 一篇自己写的promise文章,没写注释,阅读需要一点门槛。
  2. 做的功能都测试了的,没有发现问题,如有问题的话欢迎评论区留言讨论。
  3. 转载请注明初次。
<script>
  function Promise0(executor) {
    let self = this;
    self.state = 'padding';
    self.resolveValue = '';
   
    self.onResolved = [];
    self.onRejected = [];
    function resolved(value) {
      if (self.state !== 'padding') {
        return;
      }
      self.state = 'resolved';
      self.resolveValue = value;
      self.onResolved.forEach((fn) => {
        fn();
      });
    }
    function rejected(value) {
      if (self.state !== 'padding') {
        return;
      }
      self.state = 'rejected';
      self.resolveValue = value;
      self.onRejected.forEach((fn) => fn());
    }
    try {
      executor(resolved, rejected);
    } catch {
      executor(rejected);
    }
  }
  Promise0.prototype.then = function (resolve, reject) {
    resolve = typeof resolve == 'function' ? resolve : (val) => val;
    reject =
      typeof reject == 'function'
        ? reject
        : (err) => {
            throw err;
          };
    let self = this;
    let res = null;
    let Promise2 = new Promise0(function (resolved2, reject2) {
      if (self.state == 'resolved') {
        setTimeout(() => {
          try {
            res = resolve(self.resolveValue);
            if (typeof res?.then == 'function') {
              res.then.call(res, resolved2, reject2);
            } else {
              resolved2(res);
            }
          } catch (e) {
            reject2(e);
          }
        }, 0);
      } else if (self.state == 'rejected') {
        setTimeout(() => {
          try {
            res = reject(self.resolveValue);

            if (typeof res?.then == 'function') {
              res.then.call(res, resolved2, reject2);
            } else {
              resolved2(res);
            }
          } catch (e) {
            reject2(e);
          }
        }, 0);
      } else if (self.state == 'padding') {
        self.onResolved.push(() => {
          setTimeout(() => {
            try {
              res = resolve(self.resolveValue);
              if (typeof res?.then == 'function') {
                res.then.call(res, resolved2, reject2);
              } else {
                resolved2(res);
              }
            } catch (e) {
              reject2(e);
            }
          }, 0);
        });
        self.onRejected.push(() => {
          setTimeout(() => {
            try {
              res = reject(self.resolveValue);
              if (typeof res?.then == 'function') {
                res.then.call(res, resolved2, reject2);
              } else {
                resolved2(res);
              }
            } catch (e) {
              reject2(e);
            }
          }, 0);
        });
      }
    });
    return Promise2;
  };

  Promise0.prototype.catch = function (onRejected) {
    return this.then(null, onRejected);
  };
  Promise0.resolve = function (value) {
    return new Promise0(function (resolved, rejected) {
      resolved(value);
    });
  };
  Promise0.reject = function (value) {
    return new Promise0(function (resolved, rejected) {
      rejected(value);
    });
  };
  Promise0.all = function (value) {
    return new Promise0(function (resolve, reject) {
      let result = [];
      let ri = 0;
      for (let i = 0; i < value.length; i++) {
        let p = value[i];
        p.then(function (data) {
          result[i] = data;
          if (++ri === value.length) {
            resolve(result);
          }
        }, reject);
        if (p.state == 'rejected') {
          return;
        }
      }
    });
  };
  Promise0.race = function (value) {
    return new Promise0(function (resolve, reject) {
      for (let i = 0; i < value.length; i++) {
        let p = value[i];
        p.then(resolve, reject);
      }
    });
  };
  Promise0.any = function (value) {
    return new Promise0(function (resolve, reject) {
      let pCount = 0;
      for (let i = 0; i < value.length; i++) {
        let p = value[i];
        p.then(resolve, function (v) {
          pCount++;
          if (pCount === value.length) {
            reject(new AggregateError([new Error()], 'All promises were rejected'));
          }
        });
      }
    });
  };
  Promise0.allSettled = function (value) {
    return new Promise0(function (resolve, reject) {
      let pResult = [];
      for (let i = 0; i < value.length; i++) {
        let p = value[i];
        p.then(
          function (v) {
            pResult.push({ status: 'fulfilled', value: v });
            if (pResult.length === value.length) {
              resolve(pResult);
            }
          },
          function (v) {
            pResult.push({ status: 'rejected', reason: v });
            if (pResult.length === value.length) {
              resolve(pResult);
            }
          }
        );
      }
    });
  };

  pall1 = new Promise0(function (resolve, reject) {
    setTimeout(() => {
      reject('reject1');
      // resolve('resolve,pall1');
    }, 1000);
  });
  pall2 = new Promise0(function (resolve, reject) {
    //resolve('resolve2');
    setTimeout(() => {
      reject('resolve,pall2');
    }, 10);
  });
  pall3 = new Promise0(function (resolve, reject) {
    //resolve('resolve');
    setTimeout(() => {
      reject('resolve,pall3');
    }, 10);
  });
  pall4 = pall3.catch(function (v) {
    console.log('pall4', v);
    return new Promise0(function (resolve, reject) {
      reject(11111);
    });
    // return 11111;
  });
  //   pall4.then(
  //     function (v) {
  //       console.log('pall4then', v);
  //     },
  //     function (v) {
  //       console.log('pall4catch', v);
  //     }
  //   );

  //all
  //   pall = Promise0.all([pall1, pall2, pall4]);
  //   pall.then(
  //     function (v) {
  //       console.log('pallthen', v);
  //     },
  //     function (v) {
  //       console.log('pallcatch', v);
  //     }
  //   );

  //race
  //   prace = Promise0.race([pall1, pall2, pall3]);
  //   prace.then(
  //     function (v) {
  //       console.warn('pracethen', v);
  //     },
  //     function (v) {
  //       console.warn('pracethen', v);
  //     }
  //   );

  //any
  pany = Promise0.any([pall1, pall2, pall3]);
  pany.then(
    function (v) {
      console.log('pany.then', v);
    },
    function (v) {
      console.log('pany.catch', v);
    }
  );

  //allSettled
  //   pallSettled = Promise.allSettled([pall1, pall2, pall3]);
  //   pallSettled.then(
  //     function (v) {
  //       console.log('pallSettledthen', v);
  //     },
  //     function (v) {
  //       console.log('pallSettledcatch', v);
  //     }
  //   );

  //   p1 = Promise0.resolve('c');
  //   b2 = p1.then(function (v) {
  //     console.log('then', v);
  //     return ' p.then';
  //   });
  //   console.log('b2', b2);

  //   b3 = b2.then(function (v) {
  //     console.log('b2then', v);
  //     return ' b2then';
  //   });
  //   console.log('b3', b3);

  //   b4 = b3.then(function (v) {
  //     console.log('b3.then', v);
  //     return ' b3then';
  //   });
  //console.log('b4', b4);
  //   b4.then(function (v) {
  //     console.log(' b4.then', v);
  //     return ' b4then';
  //   });
</script>