Promise
类提供了四个静态方法来促进异步任务的并发.
Promise.all
接受一个 Promise 可迭代对象作为输入,并返回单个 Promise
。返回的 Promise 在所有输入的 Promise 都兑现时(包括传入的可迭代对象为空时)被兑现,其值为一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,返回的 Promise 也会被拒绝,并返回第一个拒绝的原因。
/**
* 实现Promise.all
*/
function promiseAll(promiseList) {
// 校验参数
if (!Array.isArray(promiseList)) {
throw new Error("promiseAll argument must be an array");
}
// promise为0的时候之间返回
if (promiseList.length === 0) {
return Promise.resolve([]);
}
let count = 0;
const len = promiseList.length;
const result = new Array(len);
return new Promise((resolve, reject) => {
promiseList.forEach((p, index) => {
p.then((res) => {
result[index] = res;
count++;
if (count === len) {
resolve(result);
}
}).catch((e) => {
reject(e);
});
});
});
}
Promise.allSettled
接受一个 Promise 可迭代对象作为输入,并返回单个 Promise
。返回的 Promise 在所有输入的 Promise 都敲定时兑现(包括传入的可迭代对象为空时),其值为一个描述每个 Promise 结果的对象数组。
方法返回的新的 Promise 实例,一旦发生状态变更,状态总是fulfilled,不会变成rejected。状态变成fulfilled后,它的回调函数会接收到一个数组作为参数,该数组的每个成员对应前面数组的每个 Promise 对象。
function promiseAllSetted(promiseList) {
// 校验参数
if (!Array.isArray(promiseList)) {
throw new Error("promiseAll argument must be an array");
}
// promise为0的时候之间返回
if (promiseList.length === 0) {
return Promise.resolve([]);
}
let count = 0;
const len = promiseList.length;
const result = new Array(len);
return new Promise((resolve) => {
promiseList.forEach((p, index) => {
p.then((res) => {
result[index] = {
value: res,
status: "fulfilled",
};
})
.catch((err) => {
result[index] = {
reason: err,
status: "rejected",
};
})
.finally(() => {
count++;
if (count === len) {
resolve(result);
}
});
});
});
}
Promise.any
接受一个 Promise 可迭代对象作为输入,并返回单个 Promise
。返回的 Promise 在任何输入的 Promise 兑现时兑现,其值为第一个兑现的值。如果所有输入的 Promise 都被拒绝(包括传入的可迭代对象为空时),返回的 Promise 将以带有一个包含拒绝原因的数组的 AggregateError
拒绝。
Promise.any()主要是针对只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
function promiseAny(promiseList) {
// 校验参数
if (!Array.isArray(promiseList)) {
throw new Error("promiseAll argument must be an array");
}
// promise为0的时候之间返回
if (promiseList.length === 0) {
return Promise.reject(new AggregateError([]));
}
let count = 0;
const errors = [];
const len = promiseList.length;
return new Promise((resolve, reject) => {
promiseList.forEach((p) => {
p.then(resolve).catch((err) => {
count++;
errors.push(err);
if (count === len) {
reject(new AggregateError(errors));
}
});
});
});
}
Promise.race
接受一个 Promise 可迭代对象作为输入,并返回单个 Promise
。返回的 Promise 与第一个敲定的 Promise 的最终状态保持一致。
race是竞赛赛跑的意思,竞赛肯定最受关注的就是第一名,其他的就无所谓了。
function promiseRace(promiseList) {
// 校验参数
if (!Array.isArray(promiseList)) {
throw new Error("promiseAll argument must be an array");
}
// 如果传入的是空数组,返回的就是pending状态的Promise
return new Promise((resolve, reject) => {
promiseList.forEach((p) => p.then(resolve, reject));
});
}
如何利用AbortController实现一个可取消的Promise
我们知道Promise本身是无法取消的,但是我们可以利用AbortController自己实现一个带有取消功能的Promise。
AbortController是js本身提供的Api,比较重要的是它的属性signal和方法abort。fetch方法也支持传入一个signal进行取消。具体可以看看这里:developer.mozilla.org/zh-CN/docs/…
class CancelablePromise<T> {
/**
* 构造器
* @param executor Promise中的 executor
* @param abortSignal AbortController中的signal对象
* @returns
*/
constructor(
executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void,
abortSignal: AbortSignal
) {
// 记录reject和resolve方法
let _reject: any = null;
let _resolve: any = null;
// 标志是否已经解决了
let _isExecResolve = false;
// 创建和执行Promise
const cancelablePromise = new Promise<T>((resolve, reject) => {
_reject = reject;
_resolve = (value: T) => {
_isExecResolve = true;
resolve(value);
};
return executor(_resolve, reject);
});
// 监听Signal的abourt事件
abortSignal.addEventListener('abort', () => {
if (_isExecResolve) {
return;
}
// 抛出错误
const error = new DOMException('user cancel promise', CancelablePromise.CancelExceptionName );
_reject( error );
} );
return cancelablePromise;
}
// 取消后抛出的异常名称
static CancelExceptionName = 'CancelablePromise AbortError';
}
export default CancelablePromise;
项目源码仓库: github.com/ryan6015/fr…
上一篇:前端面试--JS手写代码题(一)