此文不适合新手,适合了解一定promise a+规则的。内容对规则做了一些简略。本文可能讲的不够详细,如果有什么写的不对的地方联系我。本文是作者辛苦码出来,如有转载请标明转载链接。手撕系列代码已上传本人github
1.搭建一个架子
(function() {
var PENDING = 'pending';
var REJECT = 'rejected';
var RESOLVE = 'fulfilled';
// Promise 构造函数
function Promise() {}
// 原型方法
Promise.prototype.then = function() {}
Promise.prototype.catch = function() {}
Promise.prototype.finally = function () {}
// 静态方法
Promise.all = function () {}
Promise.allSettled = function () {}
Promise.race = function () {}
Promise.resolve = function () {}
Promise.reject = function () {}
Promise.any = function () {}
// 测试规范性:promises-aplus-tests
Promise.deferred = function () {}
// 属性
if (typeof Symbol !== undefined) Promise.prototype[Symbol.toStringTag] = 'Promise';
// 暴露API
if(typeof window !== 'undefined') window.Promise = Promise;
if(typeof module === 'object' && typeof module.exports === 'object') module.exports = Promise;
})();
2.实现简单功能
- Promise是一个构造函数,通过new该构造函数创建promise实例对象,如果不是通过new创造的实例,报错:‘this is not a promise’。new构造函数的时候传入一个函数exec,它接收两个方法类型的形参resolve和reject,如果没有传入函数,报错‘exec not a function’
- new Promise得到实例对象后,该对象默认状态为pending。在executor中调用resolve后该对象状态变为fulfilled,调用reject后该对象变为rejected状态,状态更改后不能再变
- new Promise得到的实例对象中有状态state和结果result属性。用try catch执行接收的函数,然后根据change函数改变实例的状态和值。
- then方法,then方法执行的时候需要考虑状态是否发生变化:
第一类:.then的时候已经知道了实例的状态,此时创建一个‘异步微任务’setTimeout来执行对应方法
第二类:.then的时候还不知道实例的状态(pending),此时将方法包裹一层setTimeou再包裹一个闭包存贮起来,为了确保执行顺序,后期change修改状态,通知对应其方法执行。
重点说下为什么pengding的情况下要将方法包裹一层setTimeou再包裹一个闭包存贮起来,setTimeout是为了确保顺序用的,如果直接
self.resolvedCallbacks.push(onFulfilled(self.result)),此时onFulfilled(self.result)这个方法就已经执行了
tip:queueMicrotask是用来创建 异步微任务,但是兼容性不好。所以可以拿setTimeout模拟一个异步宏任务来代替微任务
// Promise 构造函数
function Promise(exec) {
// 获取实例
var self = this;
// 考虑exec不是函数的情况
if (typeof exec !== 'function') throw new TypeError('exec not a function');
// 考虑this不是promise实例情况
if (!(self instanceof Promise)) throw new TypeError('this is not a promise');
// 状态
self.state = PENDING;
// 值
self.result = undefined;
//成功失败的回调
self.resolvedCallbacks = [];
self.rejectedCallbacks = [];
// 如果执行exec报错,状态就要变成失败
try {
exec(function resolve(value) {
change(RESOLVE, value);
}, function reject(value) {
change(REJECT, value);
});
} catch(err) {
console.log(err);
change(REJECT, err);
}
function change (state, value) {
// state的值如果发生变化不能改变
if (self.state !== PENDING) return;
self.state = state;
self.result = value;
// 执行回调
let cb = self.state === RESOLVE ? self.resolvedCallbacks : self.rejectedCallbacks;
while(cb.length) cb.shift()();
}
}
// 原型方法
Promise.prototype.then = function then(onFulfilled, onRejected) {
let self = this;
switch(self.state) {
case RESOLVE:
setTimeout(function() {
onFulfilled(self.result);
});
break;
case REJECT:
setTimeout(function() {
onRejected(self.result);
});
break;
case PENDING:
self.resolvedCallbacks.push(function() {
setTimeout(function() {
onFulfilled(self.result)
})
});
self.rejectedCallbacks.push(function() {
setTimeout(function() {
onRejected(self.result)
})
});
break;
}
}
// test 1: exec not a function
// let p1 = new Promise(1);
// test 2: this is not a promise
// let p1 = Promise((resolve, reject) => {
// resolve('succ');
// });
// test3: 状态和值
// let p1 = new Promise((resolve, reject) => {
// resolve('succ');
// reject('fail')
// })
// console.log(p1)// 最后p2输出的状态是fulfilled,值是succ。
// test4: exec报错
// let p1 = new Promise((resolve, reject) => {
// throw new Error('exec报错')
// resolve();
// })
// console.log(p1);
// test5: then是 fulfilled rejected 状态时的顺序
// let p1 = new Promise((resolve, reject) => {
// console.log('1');
// resolve('succ');
// reject('fail')
// })
// p1.then((res) => {
// console.log(res, p1);
// }, (res) => {
// console.log(res, p1);
// })
// console.log('3');
// test6: then是 pending状态时顺序
// let p2 = new Promise((resolve, reject) => {
// console.log('a');
// setTimeout(() => {
// console.log('b');
// resolve('123');
// });
// })
// p2.then((res) => {
// console.log('succ');
// console.log(res, p2);
// }, (res) => {
// console.log('fail');
// console.log(res, p2);
// })
// console.log('c');
此时其实很接近成品了,目前为止个人认为逻辑还是比较清晰简单的。接下来需要再次进阶一下
2.then方法进阶
- then方法返回一个新的Promise实例(promise2)
- 实现:把之前switch代码块放入promise2中
- promise2的成功和失败的状态取决于传入then方法的参数
Promise.prototype.then = function then(onFulfilled, onRejected) {},执行传入的函数如果也返回一个promise,那么promise2状态取决于执行传入的函数返回的promise,如果返回不是promise,直接resolve
- 实现:让onFulfilled执行,过程用try catch包裹,报错直接reject。然后看执行结果是promise还是其他值。如果是promise,就用
x.then(resolve, reject),x返回的是成功就调用resolve。
-
细节点:如果p2=p1.then(...),then返回的promise2等于p2,就会陷入循环报错'Chaining cycle detected for promise #'
-
值透传,值下沉,值顺延的问题。如果一个Promise实例p1是失败的的状态,第一个then的失败方法传了null,那么第一个then方法得到的promise实例也是失败的状态,值要顺延给第二个then的失败方法。所以我们可以在then方法里面去判断onFulfilled,onRejected是否是函数。如果不是,我们给一个默认函数,去修正本次返回的状态和上一次的状态一致,且把值传递给下一个then
-
catch方法:用于指定出错时的回调,是特殊的 then 方法,catch 之后,可以继续 then。
// 原型方法
Promise.prototype.then = function then(onFulfilled, onRejected) {
let self = this;
// 值透传
if (typeof onFulfilled !== 'function') {
onFulfilled = function (value) {
return value;
}
}
if (typeof onRejected !== 'function') {
onRejected = function (reason) {
throw reason;
}
}
let promise2 = new Promise(function(resolve, reject) {
switch(self.state) {
case RESOLVE:
setTimeout(function() {
try {
var x = onFulfilled(self.result);
// promise 死循环问题
if(x === promise2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>');
}
if (x instanceof Promise) {
x.then(resolve, reject);
return;
}
resolve(x);
} catch (e) {
reject(e);
}
}, 0);
break;
case REJECT:
setTimeout(function() {
try {
var x = onRejected(self.result);
if(x === promise2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>');
}
if (x instanceof Promise) {
x.then(resolve, reject);
return;
}
resolve(x);
} catch(e) {
reject(e)
}
}, 0)
break;
case PENDING:
self.resolvedCallbacks.push(function() {
setTimeout(function() {
try {
var x = onFulfilled(self.result);
if(x === promise2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>');
}
if (x instanceof Promise) {
x.then(resolve, reject);
return;
}
resolve(x);
} catch(e) {
reject(e)
}
}, 0)
});
self.rejectedCallbacks.push(function() {
setTimeout(function() {
try {
var x = onRejected(self.result);
if(x === promise2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>');
}
if (x instanceof Promise) {
x.then(resolve, reject);
return;
}
resolve(x);
} catch(e) {
reject(e)
}
}, 0)
});
break;
}
});
return promise2;
}
Promise.prototype.catch = function(onrejected) {
return this.then(null, onrejected);
}
// test 1: Chaining cycle detected for promise #<Promise>
// let p1 = new Promise((resolve, reject) => {
// resolve(10);
// })
// let p2 = p1.then((res) => {
// return p2;
// })
// p2.then(() => {
// console.log(p2);
// }, () => {
// console.log(p2);
// })
// Promise {state: "rejected", result: TypeError: Chaining cycle detected for promise #<Promise>...
// test2: 返回新的promise
// let p1 = new Promise((resolve, reject) => {
// resolve('11')
// })
// p1.then((val) => {
// console.log(val) // 11
// }).then((val) => {
// console.log(val) // undefined
// })
// test3: 步骤2的实现
// let p1 = new Promise((resolve, reject) => {
// resolve('11')
// })
// let p2 = p1.then(value => {
// console.log(value);
// return new Promise((resolve, reject) => {
// reject('22');
// })
// })
// let p3 = p2.then((val) => {
// console.log(val);
// }, (reason) => {
// console.log(reason);
// })
// test4: 值透传,顺延
// let p1 = new Promise((resolve, reject) => {
// reject(100)
// })
// p1.then(null, null).then((res) => {
// console.log(res)
// }, (res) => {
// console.log(res)
// })
// test5: catch
// let p1 = new Promise((resolve, reject) => {
// reject(100)
// })
// p1.catch((reason) => {
// console.log(reason);
// })
3.静态方法的实现
1.Promise.resolve:
- 如果 value 是个 thenable 对象,返回的 promise 会跟随这个 thenable 的对象,采用它的最终状态
- 如果传入的 value 本身就是 promise 对象,那么 Promise.resolve 将不做任何修改、原封不动地返回这个 promise 对象
- 其他情况,直接返回以该值为成功状态的 promise 对象
2.Promise.reject:同resolve一样
3.Promise.all:一个并发执行多个promise的方法,接收的参数是一个数组,方法返回值是一个新的promise。若传入的数组中所有的元素都是fulfilled状态的promise对象或者普通值,则返回的新promise状态为fulfilled,若传入的数组中存在Error对象或者rejected状态的promise,则方法返回的新promise状态为rejected tip:为什么要自己写isPromise方法而不是用instanceof?因为你在用Promise.all静态方法的时候不能确保这个Promise是否是你写的构造器。
4.Promise.prototype.finally:不管当前promise成功失败都会执行一次
- 实现:调用当前实例的then方法,确保当前实例不管成功和失败都能执行callback。返回一个(用Promise.resolve包裹的callback以及再用then方法把值传递下去),确保后续可以继续调用then方法。注意:包裹的callback需要立即执行,确保callback的执行
5.Promise.race: 接受一个数组,看谁跑得快返回谁,返回新一个新的promise
6.Promise.allSettled: 此方法与Promise.all相似,只是,Promise.all会有两个状态,成功/失败,而Promise.allSettled只会有一个完成状态,无论子Promise是否成功,均会调用.then参数的第一个方法
4.Promise.any: 返回数组中第一个成功的promise实例,如果全部reject,则返回一个失败的实例
8.Promise.deferred: Promise有一个配套的测试脚本,它可以帮助我们测试自己写的Promise库是否符合Promises/A+规范,使用步骤如下:
1) 安装该库
npm install -g promises-aplus-tests
2) 运行测试库,测试promise代码
promises-aplus-tests promise.js
后面这个promise.js替换为自己编写的库的入口文件。注意该文件末尾需要用commonjs的语法将promise输出module.exports = Promise,通过全局命令运行时是不接受esModule的语法的输出的
当执行完上面的命令后如果给我们打印的是下面的语句就说明我们写的这个库是能通过Promises/A+规范检测的了。
此方法在官方的Promise定义中并不存在,它是用来处理异步逻辑的另一种写法,跟常规的promise有一点点不同
Promise.prototype.finally = function (callback) {
return this.then(function(value) {
return Promise.resolve(callback()).then(function() {return value});
}, function(reason) {
return Promise.resolve(callback()).then(function() {throw reason});
})
}
function isPromise(promise) {
// promise不是null,且是一个方法或者对象且promise.then是一个方法
return promise !== null && /^(object|function)$/.test(typeof promise) &&
typeof promise.then === 'function'
}
// 静态方法
Promise.all = function (promises) {
if (!Array.isArray(promises)) throw new TypeError('promise must be array');
var count = 0;
var reslut = [];
// 返回一个promise实例
return new Promise(function(reslove, reject) {
// 遍历promises数组
promises.forEach(function(promise, index) {
// 如果不是promise实例就用变成promise实例
if (!isPromise(promise)) {
promise = Promise.resolve(promise);
}
promise.then(function(value) {
// 全部成功才可以调用reslove,此时需要一个计数器
count ++;
reslut[index] = value;
if (count >= promises.length) reslove(reslut);
}).catch(function(reason) {
// 有一个失败了调用reject
reject(reason);
})
})
});
}
Promise.any = function (promises) {
if (!Array.isArray(promises)) throw new TypeError('promise must be array');
var count = 0;
var reslut = [];
return new Promise(function(reslove, reject) {
promises.forEach(function(promise, index) {
if (!isPromise(promise)) promise = Promise.resolve(promise);
promise.then(function(value) {
reslove(value);
}).catch(function(reason) {
count ++;
reslut[index] = promise;
if (count >= promises.length) reject(reslut);
})
})
});
}
Promise.allSettled = function (promises) {
if (!Array.isArray(promises)) throw new TypeError('promise must be array');
var count = promises.length;
var reslut = [];
return new Promise(resolve => {
promises.forEach(function(promise, index) {
if (!isPromise(promise)) promise = Promise.resolve(promise);
promise.then(function(val) {
reslut[index] = { status: RESOLVE, result: val }
}, function(res) {
reslut[index] = { status: REJECT, result: res }
}).finally(function() {
count--;
if (count <= 0) {
resolve(reslut)
}
})
})
})
}
Promise.race = function(promises) {
if (!Array.isArray(promises)) throw new TypeError('promise must be array');
// 返回一个promise实例
return new Promise(function(reslove, reject) {
// 遍历promises数组
promises.forEach(function(promise, index) {
// 如果不是promise实例就用变成promise实例
if(!isPromise(promise)) promise = Promise.resolve(promise);
// 谁跑得快谁决定状态
promise.then(reslove, reject)
})
});
}
Promise.resolve = function (value) {
// if (isPromise(value)) return value;
// 解释请看Promise.reject
return new Promise(function(resolve, reject) {
resolve(value);
});
}
Promise.reject = function (reason) {
// if (isPromise(reason)) return reason;
// 看到很多文章上会写上这一层判断,但是我在测试的时候有问题的。
// 比如测试下一个内容resolvePromise就会出现问题。
// 如果这个reason的状态是成功的,那么Promise.reject会直接返回一个成功的promise
return new Promise(function(resolve, reject) {
reject(reason);
});
}
// 测试规范性:promises-aplus-tests
Promise.deferred = function () {
var result = {};
result.promise = new Promise(function (resolve, reject) {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
// test Promise.resolve和Promise.reject
// let p1 = Promise.resolve('111')
// p1.then(() => {
// console.log(p1);
// });
// let p2 = Promise.reject('222')
// p2.then(null, () => {
// console.log(p2);
// });
// test Promise.finally
// let p1 = Promise.resolve('111').finally((val) => {
// console.log('finally', val);
// }).then((v) => {
// console.log('succ', v);
// }, (r) => {
// console.log('fail', r);
// })
// let p2 = Promise.reject('222').finally((res) => {
// console.log('finally', res);
// }).then((v) => {
// console.log('succ', v);
// }, (r) => {
// console.log('fail', r);
// })
// test Promise.all
// let p1 = new Promise(resolve => {resolve(100)});
// let p2 = new Promise(resolve => {
// setTimeout(() => {
// resolve(200);
// }, 1000);
// });
// let p3 = 300;
// Promise.all([p1, p2, p3]).then(res => {
// console.log(res);
// }).catch(console.log);
// test Promise.race
// let p1 = new Promise(resolve => {
// setTimeout(() => {
// resolve(100)
// }, 500);
// });
// let p2 = new Promise((resolve, reject) => {
// reject(200);
// });
// let p3 = 300;
// Promise.race([p1, p2, p3]).then(res => {
// console.log('succ', res);
// }).catch(console.log)
// Promise.race([p1, p3, p2]).then(res => {
// console.log('succ', res);
// }).catch(console.log)
// test Promise.allSettled
// let p1 = new Promise(resolve => {resolve(100)});
// let p2 = new Promise(resolve => {
// setTimeout(() => {
// resolve(200);
// }, 1000);
// });
// let p3 = 300;
// let p4 = new Promise((resolve, reject) => {reject(400)});
// Promise.allSettled([p1, p2, p3, p4]).then(res => {
// console.log(res);
// }).catch(console.log);
// test Promise.any
// let p1 = Promise.reject('111');
// let p2 = Promise.reject('222');
// let p3 = 300;
// Promise.any([p1, p2]).then(console.log).catch(console.log)
// Promise.any([p1, p2, p3]).then(console.log).catch(console.log)
以为这样就结束了,如果执行promises-aplus-tests promise.js还是有不符合规范的地方。
4.resolvePromise 抽取灵魂
其实代码已经写的差不多,但是还缺少一些校验。我们抽取then的重复逻辑写成一个handle函数。
问题出在了then函数中的x instanceof Promise,首先我们不能确保这个x是我们写的Promise实例,这个x可能返回是别人写的myPromise实例,但是也符合a+规范。这个校验会过滤掉别人写的myPromise实例,是不对的。此时我们要校验x是个对象或者方法,而且要有then函数的存在,不然就直接resolve(x)。然后执行x.then(onfulfilled, onrejected),onfulfilled的时候可能result还是个promise,递归resolvePromise。
我们知道我们自己写的promise在resolve和reject方法中都有一个if (this.status === PENDING)的判断,也就是如果之前已经调用过一次resolve或reject的话,重复调用时会被这个if语句拦截掉直接return,那么这里为什么还要特别加这么一条规范呢?
因为这里的x除了会是我们实现的promise对象外,还有可能是使用第三方库或者别人写的promise创建出来的promise对象,是不能保证它会像我们自己的库在resolve和reject方法中加一层判断,所以我们要对这些第三方库的promise对象的行为做处理,即便第三方库的promise重复调用resolve、reject,我们的代码也只会响应一次后续不会再做处理,所以我们需要改造一下resolvePromise方法,增加一个标志位来避免promise对象状态的重复变更
这个是promise a+规范内容,可以对照着代码中resolvePromise读
- 2.3.3 x is an object or function 只有是对象或者函数,才可能有then属性,那么它才可能是一个promise
- 2.3.3.1 Let then be x.then
- 2.3.3.3.1 If/when resolvePromise is called with a value y, run [[Resolve]](promise, y)。这里x.then执行onFulfilled方法时,得到的y可能还是一个promise,所以这里需要递归调用resolvePromise以确认这里y是一个promise(如果是promise则需要等待其发生状态变更)还是一个普通值,从而决定返回的promise2的状态
- 2.3.3.3.2 If/when rejectPromise is called with a reason r, reject promise with r
- 2.3.3.2 如果在获取属性 x.then 的过程中导致抛出异常 e,则拒绝 promise 并用 e 作为拒绝原因。
- 2.3.3.3 if then is a function,call it with x as this, first argument resolvePromise, and second argument rejectPromise。如果 then 是函数,则用 x 作为 this 调用该函数,并将 resolvePromise 作为函数第一个参数,rejectPromise 作为函数第二个参数
- 2.3.3.3.3 If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.如果resolve和reject都被调用了,或者说resolve或reject被调用了多次的话,那么只有第一次调用有效,后面的调用都应该被忽略。
- 2.3.3.3.4 如果调用 then 时抛出异常 e,
- 2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已经被调用,忽略该异常。
- 2.3.3.3.4.2 否则,拒绝 promise 并以 e 作为拒绝原因。
- 2.3.3.4 If then is not a function, fulfill promise with x。then不是一个函数的话,说明then只是一个普通的属性值,那么x就只是一个普通的对象
- 2.3.4 if x is not an object or function, fulfill promise with x。x既不是对象也不是函数,那么肯定是普通值,直接resolve
以下是全部代码
(function() {
var PENDING = 'pending';
var REJECT = 'rejected';
var RESOLVE = 'fulfilled';
// Promise 构造函数
function Promise(exec) {
var self = this;
if (typeof exec !== 'function') throw new TypeError('exec not a function');
if (!(self instanceof Promise)) throw new TypeError('this is not a promise');
self.state = PENDING;
self.result = undefined;
self.resolvedCallbacks = [];
self.rejectedCallbacks = [];
try {
exec(function resolve(value) {
change(RESOLVE, value);
}, function reject(value) {
change(REJECT, value);
});
} catch(err) {
change(REJECT, err);
}
function change (state, value) {
if (self.state !== PENDING) return;
self.state = state;
self.result = value;
var cb = self.state === RESOLVE ? self.resolvedCallbacks : self.rejectedCallbacks;
while(cb.length) cb.shift()();
}
}
// 决定then返回新实例状态的函数
function handle(cb, val, promise2, resolve, reject) {
try {
var x = cb(val);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
}
function resolvePromise(x, promise2, resolve, reject) {
if(x === promise2) throw new TypeError('Chaining cycle detected for promise #<Promise>');
if (x !== null && /^(object|function)$/i.test(typeof x)) {
var then;
try {
then = x.then;
} catch (e) {
reject(e);
}
if (typeof then === 'function') {
// 增加一个flag标识该promise对象的状态是否已经变更过了
var called = false;
try {
// if (called) return;
// called = true;
// 按理来说可以把called的这个判断写到这里,但是在执行promises-aplus-tests的时候会报错。
// 难道是为了要测试then.call以一步吗?!路过的大神谁知道可以说说
then.call(x, function onfulfilled(y) {
if (called) return;
called = true;
resolvePromise(y, promise2, resolve, reject);
}, function onrejected(r) {
if (called) return;
called = true;
reject(r);
});
} catch(err) {
if (called) return;
called = true;
reject(err);
}
} else {
resolve(x);
}
} else {
resolve(x);
}
}
// 原型方法
Promise.prototype.then = function then(onFulfilled, onRejected) {
var self = this;
if (typeof onFulfilled !== 'function') {
onFulfilled = function (value) {
return value;
}
}
if (typeof onRejected !== 'function') {
onRejected = function (reason) {
throw reason;
}
}
var promise2 = new Promise(function(resolve, reject) {
switch(self.state) {
case RESOLVE:
setTimeout(function() {
handle(onFulfilled, self.result, promise2, resolve, reject);
}, 0);
break;
case REJECT:
setTimeout(function() {
handle(onRejected, self.result, promise2, resolve, reject);
}, 0)
break;
case PENDING:
self.resolvedCallbacks.push(function() {
setTimeout(function() {
handle(onFulfilled, self.result, promise2, resolve, reject);
}, 0)
});
self.rejectedCallbacks.push(function() {
setTimeout(function() {
handle(onRejected, self.result, promise2, resolve, reject);
}, 0)
});
break;
}
});
return promise2;
}
Promise.prototype.catch = function(onrejected) {
return this.then(null, onrejected);
}
Promise.prototype.finally = function (callback) {
return this.then(function(value) {
return Promise.resolve(callback()).then(function() {return value});
}, function(reason) {
return Promise.resolve(callback()).then(function() {throw reason});
})
}
function isPromise(promise) {
return promise !== null && /^(object|function)$/.test(typeof promise) &&
typeof promise.then === 'function'
}
// 静态方法
Promise.all = function (promises) {
if (!Array.isArray(promises)) throw new TypeError('promise must be array');
var count = 0;
var reslut = [];
return new Promise(function(reslove, reject) {
promises.forEach(function(promise, index) {
if (!isPromise(promise)) promise = Promise.resolve(promise);
promise.then(function(value) {
count ++;
reslut[index] = value;
if (count >= promises.length) reslove(reslut);
}).catch(function(reason) {
reject(reason);
})
})
});
}
Promise.any = function (promises) {
if (!Array.isArray(promises)) throw new TypeError('promise must be array');
var count = 0;
var reslut = [];
return new Promise(function(reslove, reject) {
promises.forEach(function(promise, index) {
if (!isPromise(promise)) promise = Promise.resolve(promise);
promise.then(function(value) {
reslove(value);
}).catch(function(reason) {
count ++;
reslut[index] = promise;
if (count >= promises.length) reject(reslut);
})
})
});
}
Promise.allSettled = function (promises) {
if (!Array.isArray(promises)) throw new TypeError('promise must be array');
var count = promises.length;
var reslut = [];
return new Promise(resolve => {
promises.forEach(function(promise, index) {
if (!isPromise(promise)) promise = Promise.resolve(promise);
promise.then(function(val) {
reslut[index] = { status: RESOLVE, result: val }
}, function(res) {
reslut[index] = { status: REJECT, result: res }
}).finally(function() {
count--;
if (count <= 0) {
resolve(reslut)
}
})
})
})
}
Promise.race = function(promises) {
if (!Array.isArray(promises)) throw new TypeError('promise must be array');
return new Promise(function(reslove, reject) {
promises.forEach(function(promise, index) {
if(!isPromise(promise)) promise = Promise.resolve(promise);
promise.then(reslove, reject)
})
});
}
Promise.resolve = function (value) {
return new Promise(function(resolve, reject) {
resolve(value);
});
}
Promise.reject = function (reason) {
return new Promise(function(resolve, reject) {
reject(reason);
});
}
// 测试规范性:promises-aplus-tests
Promise.deferred = function () {
var result = {};
result.promise = new Promise(function (resolve, reject) {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
// 属性
if (typeof Symbol !== undefined) Promise.prototype[Symbol.toStringTag] = 'Promise';
// 暴露API
if(typeof window !== 'undefined') window.Promise = Promise;
if(typeof module === 'object' && typeof module.exports === 'object') module.exports = Promise;
// test reslovePromise
// let p1 = new Promise((reslove, reject) => {
// reslove(100);
// })
// let p2 = p1.then(() => {
// return Promise.resolve(Promise.reject(200));
// })
// let p3 = p1.then(() => {
// return Promise.reject(Promise.resolve(300))
// })
// setTimeout(() => {
// console.log(p1, p2, p3);
// // p2: Promise {state: "reject", reslut: 200}
// // p3: Promise {state: "reject", reslut: Promise {state: "fulfilled", value: 300}}
// }, 500)
})();
此时执行promises-aplus-tests promise.js会全部通过