官方 Promise 还有很多API ,除了 then 方法以外还有 两个实例方法:
- Promise.prototype.catch
- Promise.prototype.finally
◾ 以及目前 Promise 规范的 六个静态方法:
- Promise.resolve
- Promise.reject
- Promise.all
- Promise.allSettled
- Promise.any
- Promise.race
下面来实现一下。
1. 实现 Promise.resolve
Promise.resolve(value) 将给定的一个值转为Promise对象。
- 如果这个值是一个 promise ,那么将返回这个 promise ;
- 如果这个值是thenable(即带有
"then"
方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态; - 否则返回的promise将以此值完成,即以此值执行
resolve()
方法 (状态为fulfilled)。
根据规范我们这样实现:
class MyPromise {
constructor(executor) {
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
//......
// resolve 静态方法
static resolve(value) {
if (value instanceof MyPromise) return value;
if (value === null) return null;
// 判断如果是MyPromise
if (typeof value === 'object' || typeof value === 'function') {
try {
// 判断是否有then方法
let then = value.then;
if (typeof then === 'function') {
return new MyPromise(then.call(value)); // 执行value方法
}
} catch (e) {
return new MyPromise((resolve, reject) => {
reject(e);
});
}
}
return value;
}
}
使用官方例子测试一下:
const MyPromise = require('./MyPromise')
const promise1 = MyPromise.resolve(123);
promise1.then((value) => {
console.log(value);
// expected output: 123
});
// Resolve一个thenable对象
var p1 = MyPromise.resolve({
then: function (onFulfill) {
onFulfill("Resolving");
}
});
console.log(p1 instanceof MyPromise) // true, 这是一个Promise对象
setTimeout(() => {
console.log('p1 :>> ', p1);
}, 1000);
p1.then(function (v) {
console.log(v); // 输出"fulfilled!"
}, function (e) {
// 不会被调用
});
// Thenable在callback之前抛出异常
// MyPromise rejects
var thenable = {
then: function (resolve) {
throw new TypeError("Throwing");
resolve("Resolving");
}
};
var p2 = MyPromise.resolve(thenable);
p2.then(function (v) {
// 不会被调用
}, function (e) {
console.log(e); // TypeError: Throwing
});
输出结果:
true
123
Resolving
TypeError: Throwing
p1 :>> myPromise {PromiseState: 'fulfilled', PromiseResult: 'Resolving', onFulfilledCallbacks: Array(1), onRejectedCallbacks: Array(1)}
测试通过!!!
2. 实现 Promise.reject
Promise.reject()
方法返回一个带有拒绝原因的Promise
对象。
class MyPromise {
constructor(executor) {
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
//......
// reject 静态方法
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
}
使用官方用例测试一下:
const myPromise = require('./promiseOtherAPI')
myPromise.reject(new Error('fail')).then(function () {
// not called
}, function (error) {
console.error(error); // Error: fail
});
输出结果:
Error: fail
测试通过!!!
3. 实现 Promise.prototype.catch
catch()
方法返回一个Promise
,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected)
相同。
事实上, calling obj.catch(onRejected)
内部calls obj.then(undefined, onRejected)
。(这句话的意思是,我们显式使用obj.catch(onRejected)
,内部实际调用的是obj.then(undefined, onRejected)
)
Promise.prototype.catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
因此我们可以这样来实现:
class myPromise {
// catch 方法
catch (onRejected) {
return this.then(null, onRejected)
}
}
就一行代码,我的天,居然这么简单!!!!!!
我们用官方例子来测试一下吧
const MyPromise = require('./MyPromise')
var p1 = new MyPromise(function (resolve, reject) {
resolve('Success');
});
p1.then(function (value) {
console.log(value); // "Success!"
throw 'oh, no!';
}).catch(function (e) {
console.log(e); // "oh, no!"
}).then(function () {
console.log('after a catch the chain is restored');
}, function () {
console.log('Not fired due to the catch');
});
// 以下行为与上述相同
p1.then(function (value) {
console.log(value); // "Success!"
return Promise.reject('oh, no!');
}).catch(function (e) {
console.log(e); // "oh, no!"
}).then(function () {
console.log('after a catch the chain is restored');
}, function () {
console.log('Not fired due to the catch');
});
// 捕获异常
const p2 = new MyPromise(function (resolve, reject) {
throw new Error('test');
});
p2.catch(function (error) {
console.log(error);
});
// Error: test
输出:
Success
Success
Error: test
oh, no!
oh, no!
after a catch the chain is restored
after a catch the chain is restored
测试通过,没毛病!!!
4. 实现 Promise.prototype.finally
finally()
方法返回一个Promise
。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise
是否成功完成后都需要执行的代码提供了一种方式。
这避免了同样的语句需要在then()
和catch()
中各写一次的情况。该方法是 ES2018 引入标准的。
由于无法知道promise的最终状态,所以finally
的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
根据规范我们这样实现:
class MyPromise {
// ....
// finally 方法
finally(f) {
return this.then((value) => {
return this.resolve(f()).then(() => value)
}, (err) => {
return this.resolve(f()).then(() => {
throw err
})
});
}
}
对,就这么简单 !
测试一下:
const MyPromise = require('./MyPromise')
let p1 = new MyPromise(function (resolve, reject) {
resolve(1)
}).then(function (value) {
console.log(value);
}).catch(function (e) {
console.log(e);
}).finally(function () {
console.log('finally');
});
输出结果:
1
finally
测试通过!!!
5. 实现 Promise.all
Promise.all()
方法接收一个promise
的iterable
类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise
实例, 输入的所有promise
的resolve
回调的结果是一个数组。
返回的这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。
Promise.all
等待所有都完成(或第一个失败)- 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise
- 如果参数中包含非 promise 值,这些值将被忽略,但仍然会被放在返回数组中,如果 promise 完成的话
(也就是如果参数里的某值不是Promise,则需要原样返回在数组里)
- 在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组,它包含所有的传入迭代参数对象的值(也包括非 promise 值)。
- 如果传入的 promise 中有一个失败(rejected),Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成
根据规范我们这样实现:
class myPromise {
/**
* Promise.all
* @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入
* @returns
*/
// all 方法
static all(args) {
// let args = iterableToArray(arr);
return new MyPromise((resolve, reject) => {
// 参数校验
if (Array.isArray(args)) {
let result = []; // 存储结果
let count = 0; // 计数器
// 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise
if (args.length === 0) {
return resolve(args);
}
args.forEach((item, index) => {
// 判断参数是否为promise
if (item instanceof MyPromise) {
item.then(value=>{
count++;
// 每个promise执行的结果存储在result中
result[index] = value;
// Promise.all 等待所有都完成(或第一个失败)
count === args.length && resolve(result);
}, reason => {
/**
* 如果传入的 promise 中有一个失败(rejected),
* Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成
*/
reject(reason);
}
)
} else {
// 参数里中非Promise值,原样返回在数组里
count++;
result[index] = item;
count === args.length && resolve(result);
}
})
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
}
function resolvePromise(promise2, x, resolve, reject) {
...
}
module.exports = myPromise;
使用官方例子测试一下:
const MyPromise = require('../MyPromise');
const promise1 = MyPromise.resolve(3);
const promise2 = 42;
const promise3 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
MyPromise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
输出结果:
(3) [3, 42, 'foo']
测试通过!!!
测试 Promise.all 的快速返回失败行为
Promise.all 在任意一个传入的 promise 失败时返回失败。例如,如果你传入的 promise中,有四个 promise 在一定的时间之后调用成功函数,有一个立即调用失败函数,那么 Promise.all 将立即变为失败。
const MyPromise = require('../MyPromise');
var p1 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
var p3 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 3000, 'three');
});
var p4 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 4000, 'four');
});
var p5 = new MyPromise((resolve, reject) => {
reject('reject');
});
MyPromise.all([p1, p2, p3, p4, p5]).then(values => {
console.log(values);
}, reason => {
console.log(reason)
});
//From console:
//"reject"
输出结果:
"reject"
测试通过 !!!
6. 实现 Promise.allSettled
Promise.allSettled(iterable)方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。
- 当你有多个彼此不依赖的异步任务成功完成时,或者你总是想知道每个promise的结果时,通常使用它。
- 相比之下,Promise.all() 更适合彼此相互依赖或者在其中任何一个reject时立即结束。
参数 iterable 是一个可迭代的对象,例如Array,其中每个成员都是Promise。
对于每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。如果值为 rejected,则存在一个 reason 。value(或 reason )反映了每个 promise 决议(或拒绝)的值。
在实现前我们需要验证一点,输入的非promise值应该怎么处理?
为此我们在 Promise.allSettled(iterable)
的参数 iterable 中传入一个非promise值,看一下 Promise.allSettled() 方法内部会怎么处理:
const promise1 = Promise.resolve(3);
const promise2 = 1;
const promises = [promise1, promise2];
Promise.allSettled(promises).
then((results) => results.forEach((result) => console.log(result)));
输出结果:
{status: 'fulfilled', value: 3}
{status: 'fulfilled', value: 1}
我们发现 Promise.allSettled() 方法内部将非 Promise 值转换成 Promise 了
那下面我们就将非 Promise 值通过 Promise.resolve 转换为 Promise 进行统一处理
根据规范我们这样实现:
class myPromise {
...
/**
* Promise.allSettled
* @param {*} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入
* @returns
*/
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
// 参数校验
if (Array.isArray(promises)) {
let result = []; // 存储结果
let count = 0; // 计数器
// 如果传入的是一个空数组,那么就直接返回一个resolved的空数组promise对象
if (promises.length === 0) return resolve(promises);
promises.forEach((item, index) => {
// 非promise值,通过Promise.resolve转换为promise进行统一处理
MyPromise.resolve(item).then(
value => {
count++;
// 对于每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。
result[index] = {
status: 'fulfilled',
value
}
// 所有给定的promise都已经fulfilled或rejected后,返回这个promise
count === promises.length && resolve(result);
},
reason => {
count++;
/**
* 对于每个结果对象,都有一个 status 字符串。如果值为 rejected,则存在一个 reason 。
* value(或 reason )反映了每个 promise 决议(或拒绝)的值。
*/
result[index] = {
status: 'rejected',
reason
}
// 所有给定的promise都已经fulfilled或rejected后,返回这个promise
count === promises.length && resolve(result);
}
)
})
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
}
使用官方例子测试一下:
const MyPromise = require('../MyPromise');
const promise1 = myPromise.resolve(3);
const promise2 = 1;
const promises = [promise1, promise2];
MyPromise.allSettled(promises).
then((results) => results.forEach((result) => console.log(result)));
setTimeout(() => {
const p1 = myPromise.resolve(3);
const p2 = new myPromise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const ps = [p1, p2];
MyPromise.allSettled(ps).
then((results) => results.forEach((result) => console.log(result)));
}, 1000);
MyPromise.allSettled([]).then((results) => console.log(results))
输出结果:
(0) []
{status: 'fulfilled', value: 3}
{status: 'fulfilled', value: 1}
{status: 'fulfilled', value: 3}
{status: 'rejected', reason: 'foo'}
测试通过 !!!
7. 实现 Promise.any
本质上,这个方法和Promise.all()是相反的。
Promise.any()
接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。
如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError
类型的实例,它是 Error 的一个子类,用于把单一的错误集合在一起。
-
如果传入的参数是一个空的可迭代对象,则返回一个 已失败(already rejected) 状态的 Promise。
- 如果传入的参数不包含任何 promise,则返回一个 异步完成 (asynchronously resolved)的 Promise。
(即将非Promise值,转换为Promise并当做成功)
- 只要传入的迭代对象中的任何一个 promise 变成成功(resolve)状态,或者其中的所有的 promises 都失败,那么返回的 promise 就会 异步地(当调用栈为空时) 变成成功/失败(resolved/reject)状态。
(如果所有Promise都失败,则报错)
注意!Promise.any() 方法依然是实验性的,尚未被所有的浏览器完全支持。它当前处于 TC39 第四阶段草案(Stage 4),对node版本要求高:node 14+`
既然是处于草案阶段的实验性 API ,如果想要在各版本浏览器中兼容性使用,那实现 Promise.any()
就很有必要 💪
根据规范我们这样实现:
class MyPromise {
...
/**
* Promise.any()
* @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入
* @returns
*/
static any(promises) {
return new myPromise((resolve, reject) => {
// 参数校验
if (Array.isArray(promises)) {
let errors = []; //
let count = 0; // 计数器
// 如果传入的参数是一个空的可迭代对象,则返回一个 已失败(already rejected) 状态的 Promise。
if (promises.length === 0) return reject(new AggregateError('All promises were rejected'));
promises.forEach(item => {
// 非Promise值,通过Promise.resolve转换为Promise
myPromise.resolve(item).then(
value => {
// 只要其中的一个 promise 成功,就返回那个已经成功的 promise
resolve(value);
},
reason => {
cout++;
errors.push(reason);
/**
* 如果可迭代对象中没有一个 promise 成功,就返回一个失败的 promise 和AggregateError类型的实例,
* AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。
*/
cout === promises.length && reject(new AggregateError(errors));
}
)
})
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
}
用其他用例测试一下该方法:
const MyPromise = require('../myPromiseFully');
/**
* 验证Promise.any()方法
*/
// console.log(new AggregateError('All promises were rejected'));
MyPromise.any([]).catch(e => {
console.log(e);
});
const pErr = new Promise((resolve, reject) => {
reject("总是失败");
});
const pSlow = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "最终完成");
});
const pFast = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "很快完成");
});
Promise.any([pErr, pSlow, pFast]).then((value) => {
console.log(value);
// 期望输出: "很快完成"
})
const pErr1 = new MyPromise((resolve, reject) => {
reject("总是失败");
});
const pErr2 = new MyPromise((resolve, reject) => {
reject("总是失败");
});
const pErr3 = new MyPromise((resolve, reject) => {
reject("总是失败");
});
MyPromise.any([pErr1, pErr2, pErr3]).catch(e => {
console.log(e);
})
输出结果:
AggregateError: All promises were rejected
AggregateError: All promises were rejected
很快完成
测试通过 !!!
8. 实现 Promise.race()
Promise.race(iterable)
方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
一个待定的 Promise 只要给定的迭代中的一个promise解决或拒绝,就采用第一个promise的值作为它的返回值,从而异步地解析或拒绝(一旦堆栈为空)。
race
函数返回一个 Promise
,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。
- 如果传的迭代是空的,则返回的 promise 将永远等待。
- 如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值。
根据规范我们这样实现:
class MyPromise {
...
/**
* Promise.race()
* @param {iterable} promises 可迭代对象,类似Array。详见 iterable。
* @returns
*/
static race(promises) {
return new myPromise((resolve, reject) => {
// 参数校验
if (Array.isArray(promises)) {
// 如果传入的迭代promises是空的,则返回的 promise 将永远等待。
if (promises.length > 0) {
promises.forEach(item => {
/**
* 如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,
* 则 Promise.race 将解析为迭代中找到的第一个值。
*/
myPromise.resolve(item).then(resolve, reject);
})
}
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
}
最后测试一下代码:
const MyPromise = require('../MyPromise');
/**
* 验证Promise.race()方法
*/
// 数组全是非Promise值,测试通过
let p1 = MyPromise.race([1, 3, 4]);
setTimeout(() => {
console.log('p1 :>> ', p1);
});
// 空数组,测试通过
let p2 = MyPromise.race([]);
setTimeout(() => {
console.log('p2 :>> ', p2);
});
const p11 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const p22 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
// // 数组里有非Promise值,测试通过
MyPromise.race([p11, p22, 10]).then((value) => {
console.log('p3 :>> ', value);
// Both resolve, but p22 is faster
});
// expected output: 10
// 数组里有'已解决的Promise' 和 非Promise值 测试通过
let p12 = MyPromise.resolve('已解决的Promise')
setTimeout(() => {
myPromise.race([p12, p22, 10]).then((value) => {
console.log('p4 :>> ', value);
});
// expected output:已解决的Promise
});
// Promise.race的一般情况 测试通过
const p13 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const p14 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
MyPromise.race([p13, p14]).then((value) => {
console.log('p5 :>> ', value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
输出结果为:
p1 :>> myPromise {PromiseState: 'pending', PromiseResult: null, onFulfilledCallbacks: Array(0), onRejectedCallbacks: Array(0)}
p2 :>> myPromise {PromiseState: 'pending', PromiseResult: null, onFulfilledCallbacks: Array(0), onRejectedCallbacks: Array(0)}
p3 :>> 10
p4 :>> 已解决的Promise
p5 :>> two
测试通过 !!!
完整代码
/**
* 在 MyPromise.js 基础上,根据规范实现了 Promise 的全部方法:
* - Promise.resolve()
* - Promise.reject()
* - Promise.prototype.catch()
* - Promise.prototype.finally()
* - Promise.all()
* - Promise.allSettled()
* - Promise.any()
* - Promise.race()
*/
// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
var iterableToArray = function (iterable) {
if (typeof Array.from === 'function') {
// ES2015+, iterables exist
iterableToArray = Array.from;
return Array.from(iterable);
}
// ES5, only arrays and array-likes exist
iterableToArray = function (x) {
return Array.prototype.slice.call(x);
};
return Array.prototype.slice.call(iterable);
}
// 新建 MyPromise 类
class MyPromise {
constructor(executor) {
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
// 储存状态的变量,初始值是 pending
state = PENDING;
// 成功之后的值
value = null;
// 失败之后的原因
reason = null;
// 存储成功回调函数
onFulfilledCallbacks = [];
// 存储失败回调函数
onRejectedCallbacks = [];
// 更改成功后的状态
resolve = (value) => {
// 只有状态是等待,才执行状态修改
if (this.state === PENDING) {
// 状态修改为成功
this.state = FULFILLED;
// 保存成功之后的值
this.value = value;
// resolve里面将所有成功的回调拿出来执行
while (this.onFulfilledCallbacks.length) {
// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空
this.onFulfilledCallbacks.shift()(value)
}
}
}
// 更改失败后的状态
reject = (reason) => {
// 只有状态是等待,才执行状态修改
if (this.state === PENDING) {
// 状态成功为失败
this.state = REJECTED;
// 保存失败后的原因
this.reason = reason;
// resolve里面将所有失败的回调拿出来执行
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(reason)
}
}
}
/**
* [注册fulfilled状态/rejected状态对应的回调函数]
* @param {function} onFulfilled fulfilled状态时 执行的函数
* @param {function} onRejected rejected状态时 执行的函数
* @returns {function} newPromsie 返回一个新的promise对象
*/
then(onFulfilled, onRejected) {
const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
const realOnRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
};
// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
const promise2 = new MyPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
try {
// 获取成功回调函数的执行结果
const x = realOnFulfilled(this.value);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
const rejectedMicrotask = () => {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
try {
// 调用失败回调,并且把原因返回
const x = realOnRejected(this.reason);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
// 判断状态
if (this.state === FULFILLED) {
fulfilledMicrotask()
} else if (this.state === REJECTED) {
rejectedMicrotask()
} else if (this.state === PENDING) {
// 等待
// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
// 等到执行成功失败函数的时候再传递
this.onFulfilledCallbacks.push(fulfilledMicrotask);
this.onRejectedCallbacks.push(rejectedMicrotask);
}
})
return promise2;
}
/**
* Promise.resolve()
* @param {[type]} value 要解析为 Promise 对象的值
*/
static resolve(value) {
if (value instanceof MyPromise) return value;
if (value === null) return null;
// 判断如果是MyPromise
if (typeof value === 'object' || typeof value === 'function') {
try {
// 判断是否有then方法
let then = value.then;
if (typeof then === 'function') {
return new MyPromise(then.call(value)); // 执行value方法
}
} catch (e) {
return new MyPromise((resolve, reject) => {
reject(e);
});
}
}
return value;
}
/**
* Promise.reject()
* @param {*} reason 表示Promise被拒绝的原因
* @returns
*/
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
/**
* Promise.prototype.catch()
* @param {*} onRejected
* @returns
*/
catch (onRejected) {
return this.then(null, onRejected)
}
/**
* Promise.prototype.finally()
* @param {*} callBack 无论结果是fulfilled或者是rejected,都会执行的回调函数
* @returns
*/
finally(f) {
return this.then((value) => {
return this.resolve(f()).then(() => value)
}, (err) => {
return this.resolve(f()).then(() => {
throw err
})
});
}
/**
* Promise.all()
* @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入
* @returns
*/
static all(args) {
// let args = iterableToArray(arr);
return new MyPromise((resolve, reject) => {
// 参数校验
if (Array.isArray(args)) {
let result = []; // 存储结果
let count = 0; // 计数器
// 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise
if (args.length === 0) {
return resolve(args);
}
args.forEach((item, index) => {
// 判断参数是否为promise
if (item instanceof MyPromise) {
item.then(value => {
count++;
// 每个promise执行的结果存储在result中
result[index] = value;
// Promise.all 等待所有都完成(或第一个失败)
count === args.length && resolve(result);
}, reason => {
/**
* 如果传入的 promise 中有一个失败(rejected),
* Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成
*/
reject(reason);
})
// MyPromise.resolve(item).then(
// value => {
// count++;
// // 每个promise执行的结果存储在result中
// result[index] = value;
// // Promise.all 等待所有都完成(或第一个失败)
// count === args.length && resolve(result);
// },
// reason => {
// /**
// * 如果传入的 promise 中有一个失败(rejected),
// * Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成
// */
// reject(reason);
// }
// )
} else {
// 参数里中非Promise值,原样返回在数组里
count++;
result[index] = item;
count === args.length && resolve(result);
}
})
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
/**
* Promise.allSettled()
* @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入
* @returns
*/
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
// 参数校验
if (Array.isArray(promises)) {
let result = []; // 存储结果
let count = 0; // 计数器
// 如果传入的是一个空数组,那么就直接返回一个resolved的空数组promise对象
if (promises.length === 0) return resolve(promises);
promises.forEach((item, index) => {
// 非promise值,通过Promise.resolve转换为promise进行统一处理
MyPromise.resolve(item).then(
value => {
count++;
// 对于每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。
result[index] = {
status: 'fulfilled',
value
}
// 所有给定的promise都已经fulfilled或rejected后,返回这个promise
count === promises.length && resolve(result);
},
reason => {
count++;
/**
* 对于每个结果对象,都有一个 status 字符串。如果值为 rejected,则存在一个 reason 。
* value(或 reason )反映了每个 promise 决议(或拒绝)的值。
*/
result[index] = {
status: 'rejected',
reason
}
// 所有给定的promise都已经fulfilled或rejected后,返回这个promise
count === promises.length && resolve(result);
}
)
})
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
/**
* Promise.any()
* @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入
* @returns
*/
static any(promises) {
return new myPromise((resolve, reject) => {
// 参数校验
if (Array.isArray(promises)) {
let errors = []; //
let count = 0; // 计数器
// 如果传入的参数是一个空的可迭代对象,则返回一个 已失败(already rejected) 状态的 Promise。
if (promises.length === 0) return reject(new AggregateError('All promises were rejected'));
promises.forEach(item => {
// 非Promise值,通过Promise.resolve转换为Promise
myPromise.resolve(item).then(
value => {
// 只要其中的一个 promise 成功,就返回那个已经成功的 promise
resolve(value);
},
reason => {
cout++;
errors.push(reason);
/**
* 如果可迭代对象中没有一个 promise 成功,就返回一个失败的 promise 和AggregateError类型的实例,
* AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。
*/
cout === promises.length && reject(new AggregateError(errors));
}
)
})
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
/**
* Promise.race()
* @param {iterable} promises 可迭代对象,类似Array。详见 iterable。
* @returns
*/
static race(promises) {
return new myPromise((resolve, reject) => {
// 参数校验
if (Array.isArray(promises)) {
// 如果传入的迭代promises是空的,则返回的 promise 将永远等待。
if (promises.length > 0) {
promises.forEach(item => {
/**
* 如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,
* 则 Promise.race 将解析为迭代中找到的第一个值。
*/
myPromise.resolve(item).then(resolve, reject);
})
}
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
}
/**
* 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理
* @param {promise} promise2 promise1.then方法返回的新的promise对象
* @param {[type]} x promise1中onFulfilled或onRejected的返回值
* @param {[type]} resolve promise2的resolve方法
* @param {[type]} reject promise2的reject方法
*/
function resolvePromise(promise, x, resolve, reject) {
// 如果相等了,说明return的是自己,抛出类型错误并返回
if (promise === x) {
return reject(new TypeError('The promise and the return value are the same'));
}
if (typeof x === 'object' || typeof x === 'function') {
// x 为 null 直接返回,走后面的逻辑会报错
if (x === null) {
return resolve(x);
}
let then;
try {
// 把 x.then 赋值给 then
then = x.then;
} catch (error) {
// 如果取 x.then 的值时抛出错误 error ,则以 error 为据因拒绝 promise
return reject(error);
}
// 如果 then 是函数
if (typeof then === 'function') {
let called = false;
try {
then.call(
x, // this 指向 x
// 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
y => {
// 如果 resolvePromise 和 rejectPromise 均被调用,
// 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
// 实现这条需要前面加一个变量 called
if (called) return;
called = true;
resolvePromise(promise, y, resolve, reject);
},
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
r => {
if (called) return;
called = true;
reject(r);
});
} catch (error) {
// 如果调用 then 方法抛出了异常 error:
// 如果 resolvePromise 或 rejectPromise 已经被调用,直接返回
if (called) return;
// 否则以 error 为据因拒绝 promise
reject(error);
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x);
}
} else {
// 如果 x 不为对象或者函数,以 x 为参数执行 promise
resolve(x);
}
}
MyPromise.deferred = function () {
var result = {};
result.promise = new MyPromise(function (resolve, reject) {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
module.exports = MyPromise;