一步步,带你手写Promise,通过PromiseA+规范的872个测试用例

545 阅读12分钟

一、Promise的定义

image.png

根据PromiseA+的定义,Promise会有三个状态,pending、fulfilled、rejected,当它的状态被固定下来,就不会被改变。

二、手写Promise

我们使用Promise的方式,一般如下

const p = new Promise(...)

可见,Promise是通过构造调用的方式来使用,所以Promise其实是个JS提供的内置函数,等同于Array、Boolean之类。

为了方便,这里使用ES6的语法糖————Class的方式来实现。

1.Promise的状态定义

Promise有三个状态,pending、fulfilled和rejected,同时我们定义的状态不想要被Promise的实例继承,所以我们在状态定义时加上了static关键字。

加上static关键字,就表示该属性不会被实例继承,而是直接通过类来调用,这就称为“静态属性”。

class Promise{
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';
}

2.Promise的构造

回想一下Promise的使用如下

const p = new Promise((resolve,reject)=>{
// someting
})

Promise的构造接受一个函数,该函数的参数是resolve方法和reject方法,所以我们在constructer里需要接收一个函数。

构造一个原生的Promise,可以发现实例上有PromiseStatePromiseResult两个属性,要让new构造返回的对象可以访问到,那么这些属性要能通过原型链访问,则需要通过this.xx定义这两个属性。

image.png
class Promise{
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor (fn) {
    this.PromiseState = Promise.PENDING;
    this.PromiseResult = undefined;
    fn();
  }
}

传递进来的resolve和reject方法其实是个形参,Promise内部需要有自己的设计逻辑,比如说改变Promise的状态并且把结果返回,所以内部需要实现自己的resolve和reject方法,并且在fn的调用时绑定。

JS的this指向是隐藏的坑,这里需要通过bind方法绑定this执行,避免非预期的结果

class Promise{
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor (fn) {
    this.PromiseState = Promise.PENDING;
    this.PromiseResult = undefined;
    fn(this.resolve.bind(this),this.reject.bind(this));
  }

  resolve (value) {
    
  }

  reject (reason) {
    
  }
}

3.resolve和reject方法

这两个方法的作用,主要是改变Promise的状态,同时把结果返回

class Promise{
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor (fn) {
    this.PromiseState = Promise.PENDING;
    this.PromiseResult = undefined;
    fn(this.resolve.bind(this),this.reject.bind(this));
  }

  resolve (value) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.FULFILLED;
      this.PromiseResult = value;
    } 
    
  }

  reject (reason) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.REJECTED;
      this.PromiseResult = reason;
    } 
  }
}

4.then方法

Promise的特点之一就是有then方法。then方法的使用如下:

const p = new Promise((resolve,reject)=>{
    resolve("会有好运");
})
p.then(
    res =>{
    //
},
reason=>{
//
})

可见then方法的参数是两个函数,我们分别命名为onFulfilledonRejected,分别在成功、失败时调用。

class Promise{
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor (fn) {
    this.PromiseState = Promise.PENDING;
    this.PromiseResult = undefined;
    fn(this.resolve.bind(this),this.reject.bind(this));
  }

  resolve (value) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.FULFILLED;
      this.PromiseResult = value;
    }   
  }

  reject (reason) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.REJECTED;
      this.PromiseResult = reason;
    } 
  }

   then (onFulfilled, onRejected) { 
    if(this.PromiseState === Promise.FULFILLED){
      onFulfilled(this.PromiseResult);
    }
    if(this.PromiseState === Promise.REJECTED){
      onRejected(this.PromiseResult);
    }
  }
}

到这里Promise的属性和方法基本完成了,我们测试一下

image.png

resolve和then方法都被执行了,但是这里其实是同步的JS线性执行,而真实场景的Promise在事件循环中是异步执行的,所以我们还需要进一步完善。

三、Promise的完善

1.报错的处理

如果在Promise的构造中有异常,是会直接调用reject将报错信息返回,如

image.png

所以,我们在构造时加上try-catch,如有异常,直接reject

constructor (fn) {
    this.PromiseState = Promise.PENDING;
    this.PromiseResult = undefined;
    try { // 这里是新加的
      fn(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }  
  }

2.then方法的完善

是不是认为then方法已经大功告成了,然而并没有。再对照Promise A+规范看一眼

image.png

这里说then方法的onFulfilledonRejected是可选的,如果不是函数,就忽略它。

忽略它,什么意思嘛?

看下我们之前版本忽略onFulfilled会有什么问题,

image.png

由此可见,我们需要写兼容逻辑。如果onFulfilledonRejected不是函数,我们需要自定义兼容函数,同时reject的报错需要透传到外部,所以需要throw一个错误出来。

class Promise{
    //...
      then (onFulfilled, onRejected) { 
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onFulfilled = typeof onRejected === 'function' ? onRejected : reason => {throw reason};
        if(this.PromiseState === Promise.FULFILLED){
          onFulfilled(this.PromiseResult);
        }
        if(this.PromiseState === Promise.REJECTED){
          onRejected(this.PromiseResult);
        }
      }
      
  }

3.异步执行

众所周知,Promise.resolvePromise.reject并不是同步执行的,而是异步执行。

来看看原生的代码执行顺序

image.png

看看我们之前写的代码的执行顺序

image.png

需要改成异步来和原生的Promise来保持一致, 用queueMicrotask来实现。

class Promise {
// ...
    then (onFulfilled, onRejected) { 
        if (this.PromiseState === Promise.FULFILLED) {
          queueMicrotask(() => {
            onFulfilled(this.PromiseResult);
          })

        }
        if (this.PromiseState === Promise.REJECTED) {
          queueMicrotask(() => {
            onRejected(this.PromiseResult);
          })
        }
      }
      
}

再测试一下,是想要的顺序了

image.png

4.回调保存

想一个问题,then()是异步执行的,如果我们也异步resolve,他们的顺序应该怎样?测试的代码如下:

console.log(1);
const p = new Promise((resolve, reject) => {
  queueMicrotask(() => {
    resolve(123);
    console.log(3);
  });
});
p.then(res => {
  console.log('then resolve', res)
}, reason => {
  console.log('then reject', reason)
})
 
console.log(2);

原生的Promise执行结果如下:

image.png

我们自己写的版本:

image.png

可以看到,then方法的输出没有被执行。

原因分析:

  1. 在创建Promise的时候,我们使用了异步resolve,这里用queueMicrotask创建了一个微任务。
  2. 在执行then方法时,因为Promise的状态没有变成fulfilled或者rejected,所以onFulfilledonRejected都没有执行
  3. 异步的resolve方法被执行,输出了数字3

我们当下需要改进的是,在resolve之后,then方法中的回调才被执行,所以then方法需要在pending的时候加逻辑,我们需要一个队列,存放变成非pending状态时再执行的函数。

class Promise{
//...

  constructor (fn) {
    this.PromiseState = Promise.PENDING;
    this.PromiseResult = undefined;
    this.onFulfilledCallback = []; // 新加的
    this.onRejectedCallback = [];// 新加的
    try { 
      fn(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
    
  }

  resolve (value) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.FULFILLED;
      this.PromiseResult = value;
      this.onFulfilledCallback.forEach((callback) => callback(value));// 新加的
    } 
    
  }

  reject (reason) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.REJECTED;
      this.PromiseResult = reason;
      this.onRejectedCallback.forEach((callback) => callback(reason));// 新加的
    } 
  }

  then (onFulfilled, onRejected) { 
    if (this.PromiseState === Promise.PENDING) { // 新加的
      this.onFulfilledCallback.push(onFulfilled(this.PromiseResult));
      this.onRejectedCallback.push(onRejected(this.PromiseResult));
    }
    //...
  }
}

再重新运行测试case,结果如下:

image.png

我们发现,then方法被执行了,但是顺序不对,原生的Promise,then方法应该要最后执行。所以,这里回调的队列中也应该存的是异步的回调。

then (onFulfilled, onRejected) { 
    if (this.PromiseState === Promise.PENDING) { 
      this.onFulfilledCallback.push(
          queueMicrotask(() => onFulfilled(this.PromiseResult))
      );
      this.onRejectedCallback.push(
          queueMicrotask(() => onRejected(this.PromiseResult))
      );
    }
    if (this.PromiseState === Promise.FULFILLED) {
      queueMicrotask(() => {
        onFulfilled(this.PromiseResult);
      })
     
    }
    if (this.PromiseState === Promise.REJECTED) {
      queueMicrotask(() => {
        onRejected(this.PromiseResult);
      })
    }
  }

再运行测试的case,结果如

image.png

可见,我们已经成功了一大半啦!

5.then的链式调用

Promise是支持链式调用的,我们用之前写好的Promise版本测试一下。

class Promise {
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor (fn) {
    this.PromiseState = Promise.PENDING;
    this.PromiseResult = undefined;
    this.onFulfilledCallback = [];
    this.onRejectedCallback = [];
    try { 
      fn(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }

  }

  resolve (value) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.FULFILLED;
      this.PromiseResult = value;
      this.onFulfilledCallback.forEach((callback) => callback(value));
    }

  }

  reject (reason) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.REJECTED;
      this.PromiseResult = reason;
      this.onRejectedCallback.forEach((callback) => callback(reason));
    }
  }

  then (onFulfilled, onRejected) {
    if (this.PromiseState === Promise.PENDING) {
      this.onFulfilledCallback.push(() => queueMicrotask(() => onFulfilled(this.PromiseResult)));
      this.onRejectedCallback.push(() => queueMicrotask(() => onRejected(this.PromiseResult)));
    }
    if (this.PromiseState === Promise.FULFILLED) {
      queueMicrotask(() => {
        onFulfilled(this.PromiseResult);
      })

    }
    if (this.PromiseState === Promise.REJECTED) {
      queueMicrotask(() => {
        onRejected(this.PromiseResult);
      })
    }
  }
}
console.log(1);
const p = new Promise((resolve, reject) => {
  queueMicrotask(() => {
    resolve(123);
    console.log(3);
  });
});
p.then(res => {
  console.log('then1 resolve', res)
}, reason => {
  console.log('then1 reject', reason)
}).then(res => {
  console.log('then2 resolve', res)
}, reason => {
  console.log('then2 reject', reason)
});

console.log(2);
image.png

发现报错了,当前是不支持链式调用的。

要实现链式调用,Promise.prototype.then方法应该要返回一个新的Promise实例,具体的实现逻辑我们看Promise A+ 规范

image.png

翻译一下

2.2.7. then 必须返回一个Promise对象

promise2 = promise1.then(onFulfilled,onRejected)
  • 2.2.7.1 如果onFulfilled或者onRejected中的任意一个返回一个x值,运行Promise的定义过程[[Resolve]](promise2,x)
  • 2.2.7.2 如果onFulfilled或者onRejected中的任意一个抛出异常epromise2需要变成rejected状态并把e当成reason.
  • 2.2.7.3 如果onFulfilled不是一个函数且promise1变成了fulfilled,promise2必须是fulfilled的,返回和promise1相同的值.
  • 2.2.7.4 如果onRejected不是一个函数且promise1变成了rejected,promise2必须是rejected的,返回和promise1相同的原因。

我们再来看看Promise处理过程的定义

image.png

翻译一下

  • 2.3 Promise定义过程

Promise定义过程是一个抽象的操作,接收一个promise和一个值作为输入,我们把它表示为[[Resolve]](promise,x)。如果x是一个thenable的对象,使用x作为promise的状态,假设x的行为至少部分像一个promise。否则,promise变成fulfilled使用x作为值。

对thenables这样的处理允许promise实现可交互,只要他暴露符合PromiseA+规范的then方法。同时允许PromiseA+ 兼容异常的情况作为reasonable的then方法。

要运行[[Resolve]](promise,x),要执行下面的步骤

  • 2.3.1 如果promisex指向同一个对象,执行reject promise并返回TypeError作为原因.
  • 2.3.2 如果x是一个promise,采用它的状态
    • 2.3.2.1 如果x是pending状态,promise必须保持pending直到x变成fulfilled或者rejected.
    • 2.3.2.2 如果x是fulfilled状态,用相同的value值把promise变成fulfilled.
    • 2.3.2.3 如果x是rejected状态,用相同的reason值把promise变成rejected.
  • 2.3.3 如果x是个对象或者函数
    • 2.3.3.1 让then变成x.then
    • 2.3.3.2 如果检索到x.then返回的结果抛出了一个异常e,rejectpromisee作为原因
    • 2.3.3.3 如果then是一个函数,把x当成this,第一个参数是resolvePromise,第二个参数是rejectPromise,当:
      • 2.3.3.3.1 当resolvePromise被调用时值为y,运行[[Resolve]](promise,y).
      • 2.3.3.3.2 当rejectPromise被调用时原因为r,用r作为原因reject.
      • 2.3.3.3.3 如果resolvePromiserejectPromise都被调用,或者同样的参数被调用多次,第一次调用的结果有最高的优先级,后面的调用将会被忽略。
      • 2.3.3.3.4 如果调用then的时候抛出了一个异常e
        • 2.3.3.3.4.1 如果resolvePromise或者rejectPromise已经被调用过,就忽略它。
        • 2.3.3.3.4.2 否则,rejectpromisee作为原因
    • 2.3.3.4 如果then不是一个函数,用x作为值fulfill promise
  • 2.3.4 如果x不是一个对象或者函数,用x作为值fulfill promise.

如果promise是resolved的同时thenable是有个一个环状的thenable原型链,这会导致[[Resolve]](promise,thenable)的递归性质使得[[Resolve]](promise,thenable)被再次调用,依据上面的算法这将会导致无限递归下去,鼓励但不是必须的,去检测这样的递归情况同时返回一个reject的promise,使用TypeError作为原因。

总结一下then方法需要返回一个Promise对象,同时这里会调用一个[[Resolve]](promise,x)的函数。

所以,接下来我们需要依据规范修改then的内部逻辑并实现[[Resolve]](promise,x)函数。

then的内部应该返回一个promise,所以有

 then (onFulfilled, onRejected) {
    const promise2 = new Promise((resolve, reject) => {
      
    });
    return promise2;
}

依据规范完善内部实现then方法,

    then (onFulfilled, onRejected) {
    const promise2 = new Promise((resolve, reject) => {
      if (this.PromiseState === Promise.PENDING) {
        this.onFulfilledCallback.push(() => queueMicrotask(() => {
          try {
            if (typeof onFulfilled !== 'function') {
              resolve(this.PromiseResult);
            } else {
              let x = onFulfilled(this.PromiseResult);
              resolvePromise(promise2, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        }
        ));
        this.onRejectedCallback.push(() => queueMicrotask(() => {
          try {
            if (typeof onRejected !== 'function') {
              reject(this.PromiseResult);
            } else {
              let x = onRejected(this.PromiseResult);
              resolvePromise(promise2, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        }));
      }
      if (this.PromiseState === Promise.FULFILLED) {
        queueMicrotask(() => {
          try {
            if (typeof onFulfilled !== 'function') {
              resolve(this.PromiseResult);
            } else {
              let x = onFulfilled(this.PromiseResult);
              resolvePromise(promise2, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        })
      }

      if (this.PromiseState === Promise.REJECTED) {
        queueMicrotask(() => {
          try {
            if (typeof onRejected !== 'function') {
              reject(this.PromiseResult);
            } else {
              let x = onRejected(this.PromiseResult);
              resolvePromise(promise2, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        })
      }
    });
    return promise2;
  }
 

接下来实现resolvePromise(promise2, x, resolve, reject)函数

 
function resolvePromise(promise2, x, resolve, reject) {
  //2.3.1 如果`promise`和`x`指向同一个对象,执行reject `promise`并返回`TypeError`作为原因
  if (promise2 === x) {
    reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
  }

  // 2.3.2 如果`x`是一个promise
  if (x instanceof Promise) {
    x.then(
      (y) => resolvePromise(promise2, y, resolve, reject),
      (r) => reject(r)
    );
  }

  // 2.3.3 如果`x`是个对象或者函数
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      let then = x.then;

      // 2.3.3.3 如果then是一个函数,把x当成this,第一个参数是resolvePromise,第二个参数是rejectPromise
      if (typeof then === 'function') {
        let called = false;
        try {
          //2.3.3.3.3 如果resolvePromise和rejectPromise都被调用,或者同样的参数被调用多次,第一次调用的结果有最高的优先级,后面的调用将会被忽略。
        
          then.call(x,
            (y) => {
              if (called) return;
              called = true;
              resolvePromise(promise2, y, resolve, reject)
            },
            (r) => {
              if (called) return;
              called = true;
              reject(r)
            });
        } catch (e) {
          //2.3.3.3.4 如果调用then的时候抛出了一个异常e
          //2.3.3.3.4.1 如果resolvePromise或者rejectPromise已经被调用过,就忽略它。
          //2.3.3.3.4.2 否则,reject promise将e作为原因
          if (called) return;
          called = true;
          reject(e)
        }

      } else {
        resolve(x);
      }

    } catch (e) {
      //2.3.3.2 如果检索到x.then返回的结果抛出了一个异常e,reject promise将e作为原因
      reject(e);
    }
  } else {
    // 2.3.4 如果x不是一个对象或者函数,用x作为值fulfill promise
    resolve(x);
  }

}

到这里,我们的Promise已经完成了,接下来要做的就是检测是否符合PromiseA+的规范

完整版代码如下:

class Promise {
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor (fn) {
    this.PromiseState = Promise.PENDING;
    this.PromiseResult = undefined;
    this.onFulfilledCallback = [];
    this.onRejectedCallback = [];
    try {
      fn(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }

  }

  resolve (value) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.FULFILLED;
      this.PromiseResult = value;
      this.onFulfilledCallback.forEach((callback) => callback(value));
    }
  }

  reject (reason) {
    if (this.PromiseState === Promise.PENDING) {
      this.PromiseState = Promise.REJECTED;
      this.PromiseResult = reason;
      this.onRejectedCallback.forEach((callback) => callback(reason));
    }
  }

  then (onFulfilled, onRejected) {
    const promise2 = new Promise((resolve, reject) => {
      if (this.PromiseState === Promise.PENDING) {
        this.onFulfilledCallback.push(() => queueMicrotask(() => {
          try {
            if (typeof onFulfilled !== 'function') {
              resolve(this.PromiseResult);
            } else {
              let x = onFulfilled(this.PromiseResult);
              resolvePromise(promise2, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        }
        ));
        this.onRejectedCallback.push(() => queueMicrotask(() => {
          try {
            if (typeof onRejected !== 'function') {
              reject(this.PromiseResult);
            } else {
              let x = onRejected(this.PromiseResult);
              resolvePromise(promise2, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        }));
      }
      if (this.PromiseState === Promise.FULFILLED) {
        queueMicrotask(() => {
          try {
            if (typeof onFulfilled !== 'function') {
              resolve(this.PromiseResult);
            } else {
              let x = onFulfilled(this.PromiseResult);
              resolvePromise(promise2, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        })
      }

      if (this.PromiseState === Promise.REJECTED) {
        queueMicrotask(() => {
          try {
            if (typeof onRejected !== 'function') {
              reject(this.PromiseResult);
            } else {
              let x = onRejected(this.PromiseResult);
              resolvePromise(promise2, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        })
      }
    });
    return promise2;
  }
 
}

function resolvePromise(promise2, x, resolve, reject) {
  //2.3.1 如果`promise`和`x`指向同一个对象,执行reject `promise`并返回`TypeError`作为原因
  if (promise2 === x) {
    reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
  }

  // 2.3.2 如果`x`是一个promise
  if (x instanceof Promise) {
    x.then(
      (y) => resolvePromise(promise2, y, resolve, reject),
      (r) => reject(r)
    );
  }

  // 2.3.3 如果`x`是个对象或者函数
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      let then = x.then;

      // 2.3.3.3 如果then是一个函数,把x当成this,第一个参数是resolvePromise,第二个参数是rejectPromise
      if (typeof then === 'function') {
        let called = false;
        try {
          //2.3.3.3.3 如果resolvePromise和rejectPromise都被调用,或者同样的参数被调用多次,第一次调用的结果有最高的优先级,后面的调用将会被忽略。
        
          then.call(x,
            (y) => {
              if (called) return;
              called = true;
              resolvePromise(promise2, y, resolve, reject)
            },
            (r) => {
              if (called) return;
              called = true;
              reject(r)
            });
        } catch (e) {
          //2.3.3.3.4 如果调用then的时候抛出了一个异常e
          //2.3.3.3.4.1 如果resolvePromise或者rejectPromise已经被调用过,就忽略它。
          //2.3.3.3.4.2 否则,reject promise将e作为原因
          if (called) return;
          called = true;
          reject(e)
        }

      } else {
        resolve(x);
      }

    } catch (e) {
      //2.3.3.2 如果检索到x.then返回的结果抛出了一个异常e,reject promise将e作为原因
      reject(e);
    }
  } else {
    // 2.3.4 如果x不是一个对象或者函数,用x作为值fulfill promise
    resolve(x);
  }

}

Promise.deferred = function() {
  let result = {};
  result.promise = new Promise((resolve, reject) => {
    result.resolve = resolve;
    result.reject = reject;
  });
  return result;
}

module.exports = Promise;

// console.log(1);
// const p = new Promise((resolve, reject) => {
//   queueMicrotask(() => {
//     resolve(123);
//     console.log(3);
//   });
// });
// p.then(res => {
//   console.log('then1 resolve', res)
// }, reason => {
//   console.log('then1 reject', reason)
// }).then(res => {
//   console.log('then2 resolve', res)
// }, reason => {
//   console.log('then2 reject', reason)
// });

// console.log(2);

六、PromiseA+规范检测

1.安装官方的测试工具包

promises-tests

yarn add  promises-aplus-tests

2.定义deferred方法

image.png

需要注意的是官方这里写着用Node.js modules导出也就是用CommonJS导出。

Promise.deferred = function() {
  let result = {};
  result.promise = new Promise((resolve, reject) => {
    result.resolve = resolve;
    result.reject = reject;
  });
  return result;
}

module.exports = Promise;

3.修改package.json文件

{ 
// package.json

 "dependencies": {
    "promises-aplus-tests": "^2.1.2"
  },
  "scripts": {
    "test": "promises-aplus-tests index"
  }
 }

项目结构如下:

image.png

4.运行测试用例

yarn test

结果如:

image.png

至此,我们的Promise大功告成啦~

七、总结

在这次的实践中,我们实现了resolverejectthenresolvePromise这四个核心的方法。这几个是一个Promise必须含有的方法。

在这个过程中,可以看到如果promise的状态已经是fulfilled或者rejected,是会直接创建新的任务放到浏览器的事件循环中,如果是pending,则会在Promise状态定下来的时候才会建立新的任务加入事件循环。