想要手撕Promise要先了解他的工作方式和使用,建议先阅读使用promise

Promise的基本特性

1、promise有三个状态:pending,resolve(也叫fulfilled)以及reject; 2、new Promise时,需要传递一个执行器函数excutor,并且立即同步执行执行器函数; 3、excuotr接受两个函数类型的参数,分别是resolvereject; 4、promise默认的状态是pending状态 5、resolve有个value值,保存成功状态的值 6、reject 有reason值,保存失败状态的值 7、promise状态只能从pending到resolve或者pending到reject,状态只能改变一次且不可逆(面试有被问到过); 8、promise只能通过then方法获取结果,then 接收两个参数,分别是成功回调onResolved和失败回调onRejected; 9、promise对象方法有catchallraceresolverejectallSettIed(新特性) 10、如果调用then时,promise已经是成功状态,则执行onResolved,参数是value 11、如果调用then时,promise已经是失败状态,则执行onRejected,参数是reason 12、如果执行器中抛出异常,那么会把异常作为参数 传递给then的失败的回调onRejected

Promise构造函数

Promise构造函数需要传的参数就是一个executor构造器函数。executor里需要传resolve和reject函数,用于改变Promise实例的状态。作为一个构造函数,最先需要实现的是其基本的架构,所以先实现最基本的功能:

new MyPromise

class MyPromise {
  constructor(executor) {
    this.status = 'pending';
    this.value;   // 成功状态的值
    this.error;   // 失败状态的值
    this.resolveCallbacks = [];
    this.rejectedCallbacks = [];
    let resolve = (res) => {
    }
    let reject = (err) => {
    }
    executor(resolve, reject)
  }
  then(onFulfilled, onRejected) {
  }
  catch() {
  }
}

完善resolve和reject还有then和catch的内容

class MyPromise {
  constructor(executor) {
    this.status = 'pending';
    this.value;   // 成功状态的值
    this.error;   // 失败状态的值
    this.resolveCallbacks = [];
    this.rejectedCallbacks = [];
    let resolve = (res) => {
      // 转变状态、执行回调
      if (this.status === 'pending') {
        this.status = 'resolved';
        this.value = res;
      }
    }
    let reject = (err) => {
      // 转变状态、执行回调
      if (this.status === 'pending') {
        this.status = 'rejected';
        this.error = err;
      }
    }
    executor(resolve, reject)
  }
  then(onFulfilled, onRejected) {
    // 本质就是若当前状态为resolved或rejected 执行对应的回调函数
    if (this.status === 'resolved') {
      onFulfilled(this.value);
    }
    if (this.status === 'rejected') {
      onRejected(this.error)
    }
  }
  catch(rejected) {
    return this.then(null, rejected)
  }
}

这样就实现了一个最基础的功能:

let pro = new MyPromise((resolve, reject) => {
  resolve('resolve');
}).then(res => {
  console.log(res);
})

console.log(pro);  // resolve

.then()及链式调用

上面then的写法存在几个问题:
1)当状态改变在异步函数中,此时执行.then无法立即执行回调,应该存储等待状态改变一起执行
2).then中的回调应该放在异步函数中,所以需要加setTimeout
3).then 返回值必须为Promise对象,所以每次异步处理的结果设为x,还需根据x决定返回的promise2的状态和值

MyPromise.then(onFulfilled, onRejected) {
    // 本质就是若当前状态为resolved或rejected 执行对应的回调函数
    let promise2;

    promise2 = new MyPromise((resolve, reject) => {
      if (this.status === 'resolved') {
        setTimeout(() => {
          let x = onFulfilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        })
      }

      if (this.status === 'rejected') {
        setTimeout(() => {
          let x = onRejected(this.error);
          resolvePromise(promise2, x, resolve, reject);
        })
      }

      if (this.status === 'pending') {
        this.resolveCallbacks.push(() => {
          setTimeout(() => {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          })
        });
        this.rejectedCallbacks.push(() => {
          setTimeout(() => {
            let x = onRejected(this.error);
            resolvePromise(promise2, x, resolve, reject);
          })
        });
      }
    })

    return promise2;
  }

函数resolvePromise的实现是Promise实现的核心,其内部包含几个重要的规则,简单概括:
1)若返回值x是数值,则返回fulfiiled状态的Promise,value为x
2)若返回值x是Promise对象,则继续递归调用
3)只有当返回值x为rejected状态的Promise对象,返回的才是失败状态的Promise

function resolvePromise(promise2, x, resolve, reject) {
  // 循环引用报错
  if (x === promise2) {
    // reject 报错抛出
    return reject(new TypeError('Chaining cycle detected for promise'));
  }
  // 锁,防止多次调用
  let called;

  // x不是null 且x是对象或者函数
  if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      // A+ 规定,声明then = x的then方法
      let then = x.then;
      // 如果then是函数,就默认是promise了
      if (typeof then === 'function') {
        // 就让then执行 第一个参数是this   后面是成功的回调 和 失败的回调
        then.call(x, y => {
          // 成功和失败只能调用一个
          if (called) return;
          called = true;
          // resolve的结果依旧是promise 那就继续递归执行
          resolvePromise(promise2, y, resolve, reject);
        }, err => {
          // 成功和失败只能调用一个
          if (called) return;
          called = true;
          reject(err);// 失败了就失败了
        })
      } else {
        resolve(x); // 直接成功即可
      }
    } catch (e) {
      // 也属于失败
      if (called) return;
      called = true;
      // 取then出错了那就不要在继续执行了
      reject(e);
    }
  } else {
    resolve(x);
  }
}

then实现的最后还需补充一些细节,比如传入的onFullfilled若不是函数,则忽略onFullfilled直接返回value;还有之前的resolve和reject加入回调数组的调用

onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : error => error;

.resolve()和.reject()

Promise还可以直接调用resolve和reject方法,其本质就是new Promise然后改变状态。

MyPromise.resolve = (value) => {
  return new MyPromise((resolve, reject) => {
    resolve(value);
  })
}

MyPromise.reject = (value) => {
  return new MyPromise((resolve, reject) => {
    reject(value);
  })
}

.all()和.race()

首先说说all()方法,其本质就是只有当参数里所有Promise对象都fulfilled才返回值,其有以下特性:
Promise.all([promise1,promise2,…])
1)仅在数组内所有promise对象都resolve,才resolve,且返回Promise对象,value是所有promise对象成功的value
2)如果有一个Promise对象reject,则返回第一个reject的promise结果
3)参数的promises只要求是可迭代对象,如果传递的不是Promise对象,则直接返回原值即可。

MyPromise.all = (promises) => {
  // promises是数组
  if (!Array.isArray(promises)) {
    throw ('必须是数组')
  }
  let res = []

  return new MyPromise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      if (promises[i].then) {
        // 是promise对象则.then
        promises[i].then(r => {
          res.push(r);
          if (res.length === promises.length) {
            // 全部成功
            return resolve(res);
          }
        }, error => {
          return reject(error);
        })
      } else {
        // 不是promise对象则直接存value
        res.push(promises[i]);
        if (res.length === promises.length) {
          // 全部成功
          return resolve(res);
        }
      }
    }
  })
}

race()方法与all相反,是只返回参数所有Promise对象最早改变状态的对象,其特性如下:
Promise.race(promises)
1)当数组中某一个Promise的状态变为fulfilled/rejected,则race返回那个Promise状态及value
2)直接把race的resolve注入到数组每个对象的回调中

MyPromise.race = (promises) => {
  return new MyPromise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(resolve, reject);
    }
  })
}
-------- 本文结束感谢阅读 --------

这里是评论区,如果你看到这段话,就是没加载出来,刷新一下~


集中精神,以气御剪