手写一个Promise/A+,完美通过官方872个测试用例 (5)

我们使用Promise/A+官方的测试工具promises-aplus-tests来对我们的MyPromise进行测试,要使用这个工具我们必须实现一个静态方法deferred,官方对这个方法的定义如下:

deferred: 返回一个包含{ promise, resolve, reject }的对象

​ promise 是一个处于pending状态的promise

​ resolve(value) 用value解决上面那个promise

​ reject(reason) 用reason拒绝上面那个promise

我们实现代码如下:

MyPromise.deferred = function() { var result = {}; result.promise = new MyPromise(function(resolve, reject){ result.resolve = resolve; result.reject = reject; }); return result; }

然后用npm将promises-aplus-tests下载下来,再配置下package.json就可以跑测试了:

{ "devDependencies": { "promises-aplus-tests": "^2.1.2" }, "scripts": { "test": "promises-aplus-tests MyPromise" } }

在跑测试的时候发现一个坑,在resolvePromise的时候,如果x是null,他的类型也是object,是应该直接用x来resolve的,之前的代码会走到catch然后reject,所以需要检测下null:

// 这个坑是跑测试的时候发现的,如果x是null,应该直接resolve if(x === null) { return resolve(x); }

这个测试总共872用例,我们写的Promise完美通过了所有用例:

image-20200326214543894

其他Promise方法

在ES6的官方Promise还有很多API,比如:

Promise.resolve

Promise.reject

Promise.all

Promise.race

Promise.prototype.catch

Promise.prototype.finally

Promise.allSettled

虽然这些都不在Promise/A+里面,但是我们也来实现一下吧,加深理解。其实我们前面实现了Promise/A+再来实现这些已经是小菜一碟了,因为这些API全部是前面的封装而已。

Promise.resolve

将现有对象转为Promise对象,如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为fulfilled。

MyPromise.resolve = function(parameter) { if(parameter instanceof MyPromise) { return parameter; } return new MyPromise(function(resolve) { resolve(parameter); }); } Promise.reject

返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。

MyPromise.reject = function(reason) { return new MyPromise(function(resolve, reject) { reject(reason); }); } Promise.all

该方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([p1, p2, p3]);

Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。当p1, p2, p3全部resolve,大的promise才resolve,有任何一个reject,大的promise都reject。

MyPromise.all = function(promiseList) { var resPromise = new MyPromise(function(resolve, reject) { var count = 0; var result = []; var length = promiseList.length; if(length === 0) { return resolve(result); } promiseList.forEach(function(promise, index) { MyPromise.resolve(promise).then(function(value){ count++; result[index] = value; if(count === length) { resolve(result); } }, function(reason){ reject(reason); }); }); }); return resPromise; } Promise.race

用法:

const p = Promise.race([p1, p2, p3]);

该方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

MyPromise.race = function(promiseList) { var resPromise = new MyPromise(function(resolve, reject) { var length = promiseList.length; if(length === 0) { return resolve(); } else { for(var i = 0; i < length; i++) { MyPromise.resolve(promiseList[i]).then(function(value) { return resolve(value); }, function(reason) { return reject(reason); }); } } }); return resPromise; } Promise.prototype.catch

Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

MyPromise.prototype.catch = function(onRejected) { this.then(null, onRejected); } Promise.prototype.finally

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpxfj.html