两个 js手写简易流程并发控制的题

最近刷论坛突然看见了这几个javaScript流程并发的题,之前碰到过但是没做出来,当时做完也没有去找相关的题解,就一直搁置着。正好这次碰到了,于是决定把这几个题弄懂。

感觉这俩题比较考察对于js中的promise以及class,function的理解,虽然第一次看会觉得绕,but熟悉之后还是比较简单的。

如有错误,欢迎指正。

问题1

题目描述

实现一个 taskpool类,其至少具有 add 方法和最大并发数 max,该 add 方法接收函数(返回值为 promise),当当前执行的任务数小于设定值 max 时,立即执行,大于 max,则等待任务空闲时执行该任务,模板任务如下:

class TaskPool {
  // 在此处写下你的实现
}

const taskpool = new TaskPool(2);

for (let i = 0; i < 10; i++) {
    const task = () => new Promise(resolve => {
        // 这里 i 的值也是以前非常高频的闭包题哦
        setTimeout(() => {
            console.log(`task${i} complete`);
            resolve(`task${i}`);
        }, 2000);
    });
    schedual.add(task);
}

// 预期输出
// 2s 后
// task0 complete
// task1 complete
// 再 2s 后
// task2 complete
// task3 complete
// 再 2s 后
// task4 complete
// task5 complete
// ...
// task8 complete
// task9 complete

 思路

整体思路感觉比较简单(看过解析后觉得简单,but自己当时没想出来hhh):用一个变量temp去记录当前执行的任务数,涉及一个队列,每次添加任务/任务执行结束,都进行以下判断:

  1. 判断temp是否小于max
  2. 若小于:temp++,第一个任务出队并执行,之行结束后,temp--,回到第一步
  3. 若大于:不处理

代码

class TaskPool {
  // 最大并发数
  max=0;
  // 当前并发数
  cur=0
  constructor(num){
    this.max=num;
  }

  //往任务队列里面添加任务,并执行run 方法
  add(task){
    this.tasks.push(task);
    this.run()
  }
  run(){
    //若还有任务&&当前并发数小于最大并发数,就执行任务
    while(this.tasks.length&&this.cur<this.max){
        const tempTask=this.tasks.shift();
        this.cur++;

        //promise的finally函数,当状态变成rejected/fullfilled的时候执行
        tempTask().finally(()=>{
            this.cur--;

            //这样保证了任务执行的顺序
            this.run();
        })
    }
  }
}

const taskpool = new TaskPool(2);




for (let i = 0; i < 10; i++) {
    const task = () => new Promise(resolve => {
        // 这里 i 的值也是以前非常高频的闭包题哦
        setTimeout(() => {
            console.log(`task${i} complete`);
            resolve(`task${i}`);
        }, 2000);
    });
    schedual.add(task);
}

// 预期输出
// 2s 后
// task0 complete
// task1 complete
// 再 2s 后
// task2 complete
// task3 complete
// 再 2s 后
// task4 complete
// task5 complete
// ...
// task8 complete
// task9 complete

问题2

题目描述

计一个函数 schedule,schedule 接收一个数量 n,返回一个新函数,新函数接受一个返回 promise 的函数数组,会按照顺序执行函数,并且同时执行的函数数量不超过 n。并且该函数的返回值是一个 promsie,该 promise 会在所有函数执行完后 resolve, 其值是函数数组的返回值按顺序构成的数组,模板任务如下:

function schedule(n) {
    // 在此处写下你的实现
}

const runTask = schedule(4);

const tasks = new Array(10).fill(0).map((x, i) => () => new Promise(resolve => {
    setTimeout(() => {
        console.log(`task${i} complete`);
        resolve(`task${i}`);
    }, 2000);
}));

runTask(tasks).then(console.log);

// 预期输出
// 2s 后
// task0 complete
// task1 complete
// task2 complete
// task3 complete
// 再2s 后
// task4 complete
// task5 complete
// task6 complete
// task7 complete
// 再2s 后
// task8 complete
// task9 complete
// ['task0', 'task1', ..., 'task9']

 思路

整体思路和上一题几乎一样,不同的是,上一题是class,这一题是function,所以一些细节需要去注意。

代码

如果要问为啥要套这么多层的return,请看模板代码中是如何调用目标函数。

function schedule(n) {
    // 在此处写下你的实现
    return function(tasks){
        //记录总任务数
        let len=tasks.length;
        //保存执行结果
        const res=[];
        // 《待执行》的任务队列
        let queue=[];
        // 正在执行的任务数
        let cur=0
        // 执行完成的任务数
        let finished=0
        
        return new Promise((resolve)=>{
            // 执行task,类似于上一题的run函数
            function runTask(){
                // 判断当前执行中的任务数量和待执行的数量
                while(cur<n&&tasks[0]){
                    const item=tasks.shift();
                    // 执行任务
                    item().then((result)=>{
                        res.push(result)
                        cur--
                        finished++;
                        //执行完后,判断是继续执行递归,还是执行结束打印res
                        if(finished==len){
                            resolve(res)
                        }else{
                            runTask(resolve)
                        }

                    })
                    cur++
                }
            }
            runTask()
        })
    }
}

参考文章:中高级前端面试必刷:三道超高频的异步并发流程控制题 - 掘金

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot的简易流程可以通过以下几个步骤来实现: 1. 创建一个新的Java项目,并导入所需的依赖。这些依赖可以包括SpringBoot的核心模块、Web模块以及其他你需要的模块。 2. 创建一个主应用程序类,通常命名为`MyApplication`。这个类需要使用`@SpringBootApplication`注解标记,以指示它是SpringBoot应用程序的入口。 3. 在主应用程序类中,可以定义一些需要的配置和组件。例如,你可以使用`@Configuration`注解创建一个配置类,使用`@Bean`注解创建一些Bean实例。 4. 编业务代码。在这个例子中,你可以创建一个`User`类来表示用户,并且定义一些操作用户的方法。 5. 启动应用程序。可以通过在主应用程序类中添加一个`main`方法,并在该方法中调用`SpringApplication.run(MyApplication.class, args)`来启动应用程序。 6. 测试应用程序。可以编一些测试类,使用JUnit或其他测试框架来测试你编的业务代码。 这样,你就可以一个简易的SpringBoot应用程序。通过编配置、组件和业务代码,并启动应用程序来测试它。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [学习SpringBoot源码之一个简易版SpringBoot](https://blog.csdn.net/xjx666666/article/details/128205845)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值