关于Promise API 的实现

手动实现 Promise API
一、Promise 手写
  • 原理:利用发布者订阅者模式 构造函数接收一个 executor 函数,并会在 new Promise() 时立即执行该函数 then时收集依赖,将回调函数收集到 成功/失败队列 executor 函数中调用 resolve/reject 函数
    resolve/reject 函数被调用时会通知触发队列中的回调
两种写法:
写法1:ES5
(function(window) {
  const PENDING = "pending";
  const RESOLVED = "resolved";
  const REJECTED = "rejected";

  function Promise(executor) {
    this.state = PENDING;
    this.data = null;
    this.callbacks = [];

    function resolve(value) {
      // Promise的状态只能改一次,所以只有pending状态时候才能执行resolve和reject
      // 当Promise的状态为resolved|rejected就不能再次改变状态了
      if (this.state !== PENDING) {
        return;
      }

      this.state = RESOLVED;
      this.data = value;

      if (this.callbacks.length > 0) {
        setTimeout(() => {
          this.callbacks.forEach(callbacksObj => {
            callbacksObj.onResolved(value);
          });
        });
      }
    }

    function reject(reason) {
      // Promise的状态只能改一次,所以只有pending状态时候才能执行resolve和reject
      // 当Promise的状态为resolved|rejected就不能再次改变状态了
      if (this.state !== PENDING) {
        return;
      }

      this.state = REJECTED;
      this.data = reason;

      if (this.callbacks.length > 0) {
        setTimeout(() => {
          this.callbacks.forEach(callbacksObj => {
            callbacksObj.onRejected(reason);
          });
        });
      }
    }

    try {
      executor(resolve.bind(this), reject.bind(this));
    } catch (e) {
      // 执行器抛出异常,Promise状态为失败,调用reject
      reject(e);
    }
  }

  Promise.prototype = {
    constructor: Promise,

    then(onResolved, onRejected) {
      // 指定默认的回调函数
      // 如果用户没有指定onRejected | onResolved 我们需要把值|异常穿透下去
      // 异常穿透的关键一步,内部会捕捉并返回一个状态失败的Promise
      onRejected =
        typeof onRejected === "function"
          ? onRejected
          : reason => {
              throw reason;
            };
      onResolved =
        typeof onResolved === "function" ? onResolved : value => value;

      // 1. then中的回调函数发生异常,then返回失败的Promise,reason为异常
      // 2. then的回调函数运行,返回非Promise值,then返回成功的Promise,value为return的值
      // 3. then的回调函数运行,返回Promise,则then返回该promise
      const self = this;

      return new Promise((resolve, reject) => {
        function handle(callback) {
          try {
            const result = callback(self.data);
            if (result instanceof Promise) {
              // 第3种情况,得到返回的promise值|原因,并改变返回的promise状态
              result.then(resolve, reject);
            } else {
              // 第2种情况
              resolve(result);
            }
          } catch (e) {
            // 第1种情况
            reject(e);
          }
        }

        if (self.state === PENDING) {
          // Promise状态为pending,先把回调函数放到队列里
          self.callbacks.push({
            onResolved() {
              handle(onResolved);
            },
            onRejected() {
              handle(onRejected);
            }
          });
        } else if (self.state === RESOLVED) {
          // Promise状态为resolved,异步执行回调函数,并通过handle改变return的Promise
          setTimeout(() => {
            handle(onResolved);
          });
        } else {
          // Promise状态为rejected,异步执行回调函数,并通过handle改变return的Promise
          setTimeout(() => {
            handle(onRejected);
          });
        }
      });
    },

    catch(onRejected) {
      // 第一个参数写null,内部会把value数据向下传递
      return this.then(null, onRejected);
    }
  };

  Promise.resolve = function(value) {
    // value 可以是Promise,也可以是值
    // Promise => 根据promise状态改变return的状态
    // 值 => 成功的Promise
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(resolve, reject);
      } else {
        resolve(value);
      }
    });
  };
  Promise.reject = function(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  };
  Promise.all = function(iterable) {
    return new Promise((resolve, reject) => {
      const arr = new Array(iterable.length);
      const counter = 0;
      iterable.forEach((p, index) => {
        // 如果iterable中有值不是promise,那么包装成promise
        Promise.resolve(p).then(
          value => {
            // 执行onResolved几次,就成功几次
            // 这里不能用value代替counter,因为所有的操作都是异步的,不能确定谁先完成,如果最后一个先完成就会出问题
            arr[index] = value;
            counter++;
            counter === arr.length ? resolve(arr) : null;
          },
          reason => {
            // 只要有一个失败,整个promise失败
            reject(reason);
          }
        );
      });
    });
  };

  Promise.all = function(iterable) {
    return new Promise((resolve, reject) => {
      let arr = [];
      iterable.forEach((p, index) => {
        Promise.resolve(p).then(
          value => {
            arr[index] = value;
            if (arr.length === iterable.length) {
              resolve(arr);
            }
          },
          reason => {
            reject(reason);
          }
        );
      });
    });
  };

  Promise.race = function(iterable) {
    return new Promise((resolve, reject) => {
      iterable.forEach(p => {
        // 如果iterable中有值不是promise,那么包装成promise
        Promise.resolve(p).then(
          value => {
            // 先成功,先调用,后续的不再改变状态
            resolve(value);
          },
          reason => {
            // 先失败,先调用,后续的不再改变状态
            reject(reason);
          }
        );
      });
    });
  };

  // 自定义工具方法
  Promise.resolveDelay = function(value, time) {
    /**
     *  返回一个成功的Promise对象,它在指定时间后才能成功
     */
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (value instanceof Promise) {
          value.then(resolve, reject);
        } else {
          resolve(value);
        }
      }, time);
    });
  };

  Promise.rejectDelay = function(reason, time) {
    /**
     *  返回一个Promise对象,它在指定时间后才能确定失败
     */
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(reason);
      }, time);
    });
  };

  window.Promise = Promise;
})(window);
写法二:ES6 class
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";

class Promise {
  constructor(executor) {
    this.state = PENDING;
    this.data = null;
    this.callbacks = [];

    let resolve = value => {
      if (this.state !== PENDING) {
        return;
      }
      this.state = RESOLVED;
      this.data = value;
      if (this.callbacks.length) {
        process.nextTick(() => {
          this.callbacks.forEach(item => {
            item.onResolved(this.data);
          });
        });
      }
    };

    let reject = reason => {
      if (this.state !== PENDING) {
        return;
      }
      this.state = REJECTED;
      this.data = reason;
      if (this.callbacks.length) {
        process.nextTick(() => {
          this.callbacks.forEach(item => {
            item.onRejected(this.data);
          });
        });
      }
    };

    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }

  then(onResolved, onRejected) {
    onResolved = typeof onResolved === "function" ? onResolved : value => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : reason => {
            throw reason;
          };

    return new Promise((resolve, reject) => {
      let handle = callback => {
        try {
          const result = callback(this.data);
          if (result instanceof Promise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      };

      if (this.state === PENDING) {
        this.callbacks.push({
          onResolved() {
            handle(onResolved);
          },
          onRejected() {
            handle(onRejected);
          }
        });
      } else if (this.state === RESOLVED) {
        process.nextTick(() => {
          handle(onResolved);
        });
      } else {
        process.nextTick(() => {
          handle(onRejected);
        });
      }
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

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

  static reject(reason) {
    return new Promise((resolve, reject) => {
      if (reason instanceof Promise) {
        reason.then(reject, reject);
      } else {
        reject(reason);
      }
    });
  }

  static all(iterable) {
    return new Promise((resolve, reject) => {
      const arr = [];
      let counter = 0;
      iterable.forEach((p, index) => {
        Promise.resolve(p).then(
          value => {
            counter++;
            arr[index] = value;
            if (counter === iterable.length) {
              resolve(arr);
            }
          },
          reason => {
            reject(reason);
          }
        );
      });
    });
  }
}

module.exports = Promise;
二、Promise.all() 手写
  • Promise.all() API 的功能:Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。
  • 实现思路:首先需要将输入数组中的所有 Promise 对象均运行起来;在有 Promise 对象 resolve 后,判断是否所有对象均已 resolve,当所有 Promise 均被 resolve 后进行整体的 resolve;此外,当任何一个 Promise 对象出现 reject 后,直接 reject
function myPromiseAll(promise) {
  if (!Array.isArray(promise)) {
    // PromiseAll的入参必须是数组
    return reject(new TypeError("promise must be an array"));
  }
  let result = [];
  let count = 0;
  return new Promise((resolve, reject) => {
    // 执行所有的 Promise 对象
    promise.forEach(item => {
      Promise.resolve(item)
        .then(res => {
          result.push(res);
          count++;
          if (count == promise.length) {
            // 当所有 Promise 都 resolve 之后,统一 resolve
            resolve(result);
          }
        })
        .catch(err => {
          // 只要有任何 Promise 出现 reject, Promise.newAll 就直接 reject
          reject(err);
        });
    });
  });
}
三、Promise.race() 手写
  • Promise.race() API 的功能:Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。
  • 实现思路:Promise.race() 实际上相当于一个竞速过程,第一给被 resolvereject 的对象会被 resolvereject。因此,只需要将上面 Promise.all 的代码进行些许的改动即可
function myPromiseRace(promise) {
  return new Promise((resolve, reject) => {
    // 执行所有的 Promise 对象
    promise.forEach(item => {
      Promise.resolve(item)
        .then(res => {
          // 出现第一个被 resolve 的直接 resolve
          resolve(res);
        })
        .catch(err => {
          // 出现第一个被 reject 的直接 reject
          reject(err);
        });
    });
  });
}
四、Promise.allSettled() 手写
  • Promise.allSettled() API 的功能:Promise.allSettled() 方法返回一个在所有给定的 promise 已被决议或被拒绝后决议的 promise,并带有一个对象数组,每个对象表示对应的promise 结果。

  • 实现思路:首先同样运行所有的 Promise 对象,与 Promise.all 不同的是,在有 Promisereject 之后,我们不会直接 reject,而是记录下该 reject 的值和对应的状态 rejected;同样地,当 Promise 对象被 resolve 时我们也不仅仅局限于记录值,同时也会记录状态 fulfilled。当所有的 Promise 对象都已决(解决或拒绝)后,我们统一 resolve 记录了值(value)已决状态(status)的数组。

function myPromiseAllSettled(promise) {
  let result = [];
  let count = 0;
  return new Promise(resolve => {
    // 执行所有的 Promise 对象
    promise.forEach(item => {
      Promise.resolve(item)
        .then(res => {
          // 当有 Promise 被 resolve 之后,记录 resolve 值和状态,已决 Promise 计数加一
          result.push({ status: "fulfilled", value: res });
          count++;
          if (count == promise.length) {
            // 全部 Promise 已决,resolve
            resolve(result);
          }
        })
        .catch(err => {
          // 当有 Promise 被 reject 后,记录 reject 值和状态,并且已决的 Promise 计数加一
          result.push({ status: "rejected", value: err });
          count++;
          if (count == promise.length) {
            // 全部 Promise 已决,resolve
            resolve(result);
          }
        });
    });
  });
}

转载于: https://blog.csdn.net/qq_42552393/article/details/117000022#comments_16549335

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值