手写支持设置最大并发数的promise处理函数

本文介绍了如何手写一个函数,该函数接收Promise数组和最大并发数作为参数,按顺序处理Promise并返回包含所有结果(包括resolve和reject)的数组。文章详细分析了参数校验、异常处理以及处理单个Promise的逻辑,并提供了完整的代码实现。
摘要由CSDN通过智能技术生成

前言

今天是大年初一,祝大家新年快乐,新的一年技术水平不断提升,工作顺心顺意,都升职加薪,写代码没bug。大年初一是放松心情,尽情玩耍的日子,但是这个假期也别忘了提升自己的技术哦。
今天我们就来聊一聊手写支持设置最大并发数的promise处理函数。这应该是一个比较常见的面试题,之前笔者也在面试某大厂的时候遇到过这个codding的题目。废话不多说,我们进入正题

题目

手写一个函数,该函数接收两个函数,一个是promise数组,另一个是设置的最大并发数;当所有的promise对象都处理完成之后,返回一个包含了所有结果的数组,结果数组顺序需要与原始promise数组顺序一样;如果某一个promise对象reject了,也要把reject原因放入结果数组中

分析

首先,我们分析这个题目的入参出参,入参已经确定,出参肯定返回一个新的Promise对象,并且这个对象一定是resolve的;所以可以先把函数整体框架搭好;

function concurrentPromise(promises,max){
	return new Promise(reslove=>{
		// 详细代码
	})
}

其次,我们考虑一些异常场景。当传入的第一个参数不是数组,或者是数组但不是promise数组时是我们针对promise的一些处理是会有异常的,所以针对入参我们需要做一些校验;

function concurrentPromise(promises,max){
	// 如果传入的不是一个数组,抛出异常
     if (!Array.isArray(promises)) {
       throw new Error("请传入promise数组");
     }
     // 如果传入数组中不全是Promise对象,抛出异常
     const isAllPromise = promises.every((v) => {
       return v instanceof Promise;
     });
     if (!isAllPromise) {
       throw new Error("请传入promise数组");
     }
     if (typeof max !== "number") {
       throw new Error("请传入正确的最大并发数");
     }
	return new Promise(reslove=>{
		// 详细代码
	})
}

再次,对于promise对象,我们肯定是一个一个单独处理,处理完一个才处理下一个,所以我们需要一个函数来处理单个的promise对象,然后对于当前是处理的哪个promise对象也需要做好标记,因此,我们可以先写出如下代码:

function concurrentPromise(promises,max){
	// 如果传入的不是一个数组,抛出异常
     if (!Array.isArray(promises)) {
       throw new Error("请传入promise数组");
     }
     // 如果传入数组中不全是Promise对象,抛出异常
     const isAllPromise = promises.every((v) => {
       return v instanceof Promise;
     });
     if (!isAllPromise) {
       throw new Error("请传入promise数组");
     }
     if (typeof max !== "number") {
       throw new Error("请传入正确的最大并发数");
     }
	return new Promise(reslove=>{
		// 存放所有promise对象结束pending状态后的结果
        const result = [];
        // 当前处理的promise对象的下标
        let index = 0;
        // 已经处理的promise对象的个数
        let count = 0;
        // 处理单个promise的方法
        async function handlePromise() {
          // 如果所有的promise对象都已经取出处理过了,那么就直接返回
          if (index >= len) {
            return;
          }
          // 取出将要处理的promise对象
          const promise = promises[index];
          // 存储当前处理的promise对象在数组中的索引,放入result数组中时需要对应上
          const i = index;
          // 处理完这个promise对象后,下标需要加1,下一次就调用函数时需要取出下一个promise对象去处理
          index++;
          try {
            const res = await promise.then();
            // 拿到结果之后将结果存入result数组中,下标要对应上
            result[i] = res;
          } catch (error) {
            // 就算promise对象reject了,也需要把reject原因存入result数组中
            result[i] = error;
          } finally {
            // 每处理完一个promise对象,count都需要自增1
            count++;
            // 如果所有的promise对象都处理完了,那么把结果resolve出去即可
            if (count === len) {
              resolve(result);
            } else {
              // 处理完这个promise对象时,调用函数处理下一个promise对象
              handlePromise();
            }
          }
        }
	})
}

最后,我们只需要考虑一开始需要调用几次handlePromise方法,然后一开始的时候调用几次就好;因为考虑到max > promises.length的场景,只需要调用promise.length次即可,代码实现如下:

// 初始化调用handlePromise函数的次数,有可能max比数组长度大
 const times = Math.min(len, max);
 for (let i = 0; i < times; i++) {
   handlePromise();
 }

完整代码实现

function concurrentPromise(promises, max) {
   // 如果传入的不是一个数组,抛出异常
   if (!Array.isArray(promises)) {
     throw new Error("请传入promise数组");
   }
   // 如果传入数组中不全是Promise对象,抛出异常
   const isAllPromise = promises.every((v) => {
     return v instanceof Promise;
   });
   if (!isAllPromise) {
     throw new Error("请传入promise数组");
   }
   if (typeof max !== "number") {
     throw new Error("请传入正确的最大并发数");
   }
   // 返回一个Promise对象
   return new Promise((resolve) => {
     const len = promises.length;
     if (len === 0) {
       resolve([]);
     }
     // 存放所有promise对象结束pending状态后的结果
     const result = [];
     // 当前处理的promise对象的下标
     let index = 0;
     // 已经处理的promise对象的个数
     let count = 0;
     // 处理单个promise的方法
     async function handlePromise() {
       // 如果所有的promise对象都已经取出处理过了,那么就直接返回
       if (index >= len) {
         return;
       }
       // 取出将要处理的promise对象
       const promise = promises[index];
       // 存储当前处理的promise对象在数组中的索引,放入result数组中时需要对应上
       const i = index;
       // 处理完这个promise对象后,下标需要加1,下一次就调用函数时需要取出下一个promise对象去处理
       index++;
       try {
         const res = await promise.then();
         // 拿到结果之后将结果存入result数组中,下标要对应上
         result[i] = res;
       } catch (error) {
         // 就算promise对象reject了,也需要把reject原因存入result数组中
         result[i] = error;
       } finally {
         // 每处理完一个promise对象,count都需要自增1
         count++;
         // 如果所有的promise对象都处理完了,那么把结果resolve出去即可
         if (count === len) {
           resolve(result);
         } else {
           // 处理完这个promise对象时,调用函数处理下一个promise对象
           handlePromise();
         }
       }
     }
     // 初始化调用handlePromise函数的次数,有可能max比数组长度大
     const times = Math.min(len, max);
     for (let i = 0; i < times; i++) {
       handlePromise();
     }
   });
 }
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值