【面试高频】手写 Promise 四大并发方法

手写 Promise 并发方法解析

Promise 的并发方法: all,allSettled,any,race。这些方法都会接受 promises 数组,返回一个新的 Promise。

Promise.all

成功:所有传入的 promise 状态都为 fulfilled,传回所有的成功的结果数组

失败:只要有一个 promise 状态为 rejected,直接传回失败结果

核心特征(独立、缺一不可):

  • 业务逻辑依赖所有任务的成功结果(缺一不可)

  • 快速失败(任一任务失败则整体终止,无需等待其他任务)

适用场景:

  • 资源预先加载

  • 依赖多接口数据加载

function PromiseAll(promises) {
	return new Promise((resolve, reject) => {
		if(!Array.isArray(promises)) {
			reject(new TypeError('输入参数错误'));
		}

		let n = promises.length;
		let results = new Array(n);
		let fullfilledCnt = 0;
		if(n == 0) {
			return resolve(results);
		}

		promises.forEach((promise, i)=> {
			Promise.resolve(promise).then(result => {
				results[i] = result;
				fullfilledCnt ++;
				if(fullfilledCnt == n) {
					resolve(results);
				}
			}).catch(err => {
				reject(err);
			});
		});
	});
};

// const p1 = Promise.resolve(1);
// const p2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
// PromiseAll([p1, p2]).then(console.log); // [1, 2](约1m后)

// const p3 = Promise.reject('出错了');
// PromiseAll([p1, p3]).catch(console.error); // '出错了'(立即)

Promise.allSettled

成功:所有传入的 promise 状态都为 fulfilled 或 rejected,传回结果为数组,包含状态以及成功或失败的结果

核心特征:完整结果反馈; 不因单个失败而中断

适用场景:

  • 日志上传

  • 非核心资源预加载

function PromiseAllSettled(promises) {
	return new Promise((resolve, reject) => {
		if(!Array.isArray(promises)) {
			reject(new TypeError('输入参数错误'));
		}

		let n = promises.length;
		let results = new Array(n);
		let cnt = 0;
		if(n == 0) {
			return resolve(results);
		}

		promises.forEach((promise, i)=> {
			Promise.resolve(promise).then(value => {
				results[i] = { stats: 'fullfilled', value };
			}).catch(error => {
				results[i] = { stats: 'rejected', error };
			}).finally(() => {
				cnt ++;
				if(cnt == n) {
					resolve(results);
				}
			});
		});
	});
};

// const promise1 = Promise.resolve(3);
// const promise2 = Promise.reject(new Error('Promise 2 failed'));
// const promise3 = new Promise((resolve) => {
//   setTimeout(resolve, 100, 'foo');
// });

// PromiseAll([promise1, promise2, promise3])
//   .then(values => {
//     console.log(values); // 不会执行
//   })
//   .catch(error => {
//     console.error(error); // 输出: Error: Promise 2 failed
//   });

Promise.any

成功:第一个完成的 promise 的状态为 fulfilled,返回成功结果

失败:所有 promise 状态为 rejected,返回失败的数组

特征:结果单一性;全败才败(兜底)

场景:多源数据兜底获取、多节点服务器可用性检测

function PromiseAny(promises) {
	return new Promise((resolve, reject) => {
		if(!Array.isArray(promises)) {
			reject(new TypeError('输入参数错误'));
		}

		let n = promises.length;
		if(n == 0) return;
		let rejectCnt = 0;
		let errors = new Array(n);

		promises.forEach((promise, i)=> {
			Promise.resolve(promise).then(value => {
				resolve(value);
			}).catch(error => {
				rejectCnt ++;
				errors[i] = error
				if(rejectCnt == n) {
					reject(new AggregateError(error, "所有promises都被rejected"));
				}
			});
		});
	});
};


// const resolveAfter = (value, delay) => 
//   new Promise(resolve => setTimeout(() => resolve(value), delay));

// const rejectAfter = (reason, delay) => 
//   new Promise((_, reject) => setTimeout(() => reject(reason), delay));


// // 有一个成功(第一个成功的结果被返回)
// const test1 = async () => {
//   const p1 = rejectAfter('p1失败', 100);
//   const p2 = resolveAfter('p2成功', 200); 
//   const p3 = resolveAfter('p3成功', 150);
//   try {
//     const result = await PromiseAny([p1, p2, p3]);
//     console.log('测试1结果:', result);
//   } catch (err) {
//     console.error('测试1错误:', err);
//   }
// };

// test1();

Promise.race

成功:第一个完成的 promise 的状态为 fulfilled,返回成功结果

失败:第一个完成的 promise 的状态为 rejected,返回失败结果

特征:竞速性,最快的响应结果,结果具有单一性

场景:cdn 命中(要的就是最快的响应);用户请求同一接口(避免重复刷新);接口请求超时


function PromiseRace(promises) {
	return new Promise((resolve, reject) => {
		if(!Array.isArray(promises)) {
			reject(new TypeError('输入参数错误'));
		}

		let n = promises.length;
		if(n == 0) return;


		promises.forEach((promise, i)=> {
			Promise.resolve(promise).then(value => {
				resolve(value);
			}).catch(error => {
				reject(error);
			});
		});
	});
};


// // 测试正常场景
// const p1 = new Promise(resolve => setTimeout(() => resolve(1), 100));
// const p2 = Promise.resolve(2);
// PromiseRace([p1, p2]).then(console.log); // 2(立即,p2先成功)

// // 测试失败场景
// const p3 = Promise.reject('出错了');
// const p4 = new Promise(resolve => setTimeout(resolve, 200));
// PromiseRace([p4, p3]).catch(console.error); // '出错了'(立即,p3先失败)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值