两个 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.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{
                        res.push(result)
                        cur--
                        finished++;
                        //执行完后,判断是继续执行递归,还是执行结束打印res
                        if(finished==len){
                            resolve(res)
                        }else{
                            runTask(resolve)
                        }

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

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

你可能感兴趣的:(javascript,开发语言,ecmascript,前端,算法)