《手写Promise》

180 阅读3分钟

根据Promise A+规范来实现一个简易的Promise

首先 new Promise()得到的是一个对象

class Promise{

}

module.exports = Promise

Promise对象的输入是函数

关于输入有三个要求:

  1. 检查类型:Promise的输入必须是一个函数,否则报错

  2. 立刻执行传下来的函数

  3. 函数有两个参数,分别是resolve和reject

class Promise2 {
    resolve(result) {
   }

  reject(reason) {
   }

  constructor(fn) {
    if (typeof fn !== 'function') {
      throw new Error('Promise必须接受一个函数');
    }
    //传进来的函数就会被立刻调用,第一个参数是this.resolve, 第二个参数是this.reject
    fn.call(this, this.resolve.bind(this), this.reject.bind(this));
  }

Promise对象的输出是带有then方法的对象

所以我们继续完善then方法

then方法有以下要求:

  1. 接受两个参数, success 和 fail
  2. 如果两个参数没有传,或者类型不是函数,不报错,但是也不会执行什么操作
  3. 同一个promise可以多次调用then
    promise1.then
    promise1.then
  4. then 的两个参数 是让 resolve和reject去调用的

为了处理可能多次调用then的情况,我们用一个数组callbacks储存多次then传进来的参数,用一个数组handle存储每次then的传进来的参数

then(succeed?, fail?) {
    let handle = [];
    if (typeof succeed === 'function') {
      handle[0] = succeed;
    }

    if (typeof fail === 'function') {
      handle[1] = fail;
    }

    this.callbacks.push(handle);
  }

用Resolve调用then的第一个参数

resolve函数需要做两件事:

  1. 修改Promise的状态,并且保证resolve函数只能执行一次
  2. 调用then的第一个参数
  resolve(result) {
    // 保证resolve只能被调用一次,如果状态不是‘pending’就直接退出
    if (this.state !== 'pending') {
      return;
    }
    this.state = 'fulfilled';
    setTimeout(() => {
      this.callbacks.forEach(handle => {
        if (typeof handle[0] === 'function') {
          handle[0].call(undefined, result);
        }
      });

    });

  }

用Reject调用then的第二个参数

reject函数也需要做两件事:

  • 修改Promise的状态,并且保证reject函数只能执行一次
  • 调用then的第二参数
 reject(reason) {
    // 保证reject只能被调用一次
    if (this.state !== 'pending') return;
    this.state = 'rejected';
    setTimeout(() => {
      this.callbacks.forEach(handle => {
        if (typeof handle[1] === 'function') {
          handle[1].call(undefined, reason);
        }
      });
    });

  }

最终完成的Promise就是:

class Promise2 {
  state = 'pending';
  callbacks = [];

  resolve(result) {
    // 保证resolve只能被调用一次
    if (this.state !== 'pending') {
      return;
    }
    this.state = 'fulfilled';
    // 异步调用then的第一个参数
    setTimeout(() => {
      this.callbacks.forEach(handle => {
        if (typeof handle[0] === 'function') {
          handle[0].call(undefined, result);
        }
      });

    });

  }

  reject(reason) {
    // 保证reject只能被调用一次
    if (this.state !== 'pending') return;
    this.state = 'rejected';
     // 异步调用then的第二个参数
    setTimeout(() => {
      this.callbacks.forEach(handle => {
        if (typeof handle[1] === 'function') {
          handle[1].call(undefined, reason);
        }
      });
    });

  }

  constructor(fn) {
    if (typeof fn !== 'function') {
      throw new Error('Promise必须接受一个函数');
    }
    //传进来的函数就会被立刻调用
    fn.call(this, this.resolve.bind(this), this.reject.bind(this));
  }

  then(succeed?, fail?) {
    let handle = [];
    if (typeof succeed === 'function') {
      handle[0] = succeed;
    }

    if (typeof fail === 'function') {
      handle[1] = fail;
    }

    this.callbacks.push(handle);
  }


}

export default Promise2;

实现Promise.all

思路:

首先分析输入输出

输入:数组,可能有字符串,数字,Promise对象

输出:一个Promise对象

然后分析promise.all的特性:

数组里的全部元素成功,才算成功

有一个失败,立刻reject

所以遍历数组时,用一个空数组results记录每次的结果,如果results的数组长度 和 输入的数组长度一致,就表示都成功,就resolve这个数组

反之,遍历时如果有一个失败就reject

   all(promises){
     
     // 返回一个Promise对象
    return new Promise((resolve, reject)=>{
      // 考虑极端情况,如果是空数组直接返回
      if(promises.length === 0) {
        resolve([])
      }else {
        let results = []
        for (let i = 0; i < promises.length; i++) {
          promises[i] = promises[i] instanceof Promise? promises[i]: Promise.resolve(promises[i])
          // 用then 去拿结果
          promises[i].then((result)=>{
            results.push(result)
            // 只有等到都成功了才一起resolve
            if(result.length === promises.length){
              resolve(results)
            }
          },(err)=>{
            reject(err)
          })

        }
      }

    })
  }

实现Promise.race

/**
   * Promise.race
   * @description 只要有一个promise对象进入FULFILLED 或者  REJECTED 状态的话,就会继续执行后面的处理
   * @param {*} values  接受promise对象组成的数组作为参数
   * @returns 返回一个Promise实例
   */
  static race(values) {
    return new Promise((resolve, reject) => {
      values.forEach((promise) => {
        promise.then(resolve, reject)
      })
    })
  }

实现Promise.reject和Promise.resolve

  // 默认产生一个成功的promise
  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value)
    })
  }
  // 默认产生一个失败的promise
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

参考:

github.com/lgwebdream/…