(面试题)JS实现一个任务队列

这是一道 cvte 的面试题,我当时没有做出来,所以想记录下来,一方面是为了总结思考问题的方法,另一方面便于日后回顾。

题目

要求:根据题目描述及输出结果补全 queue 方法。

function fun1(cb) {
  setTimeout(() => {
    console.log('1');
    cb();
  }, 300);
}

function fun2(cb) {
  setTimeout(() => {
    console.log('2');
    cb();
  }, 250);
}

function fun3(cb) {
  setTimeout(() => {
    console.log('3');
    cb();
  }, 150);
}

function queue(list, count) {

}

queue([fun1, fun2, fun3], 2);   // 依次输出 2、1、3

说明

  1. fun1fun2fun3 表示三个待执行的任务,参数:
  • cb: 回调函数
  1. queue 为执行任务的方法,参数:
  • list: 待执行任务数组
  • count: 可同时执行的最大任务数

简单来说,比如在银行办理业务,当前有 2 个窗口,有 3 个人需要办理业务,但是窗口只能容纳两个人,所以需要排队叫号。当某个窗口的人业务办理完毕以后,下一个人就到这个窗口办理业务。

分析

过程

queue 方法执行后,fun1fun2 同时开始执行,fun2 先执行完,接着 fun3 开始执行。

思路

每个方法执行完后,会执行回调函数 cb,有什么用呢?

表明当前任务执行完毕。

那么,当前任务执行完毕后,应该做什么呢?

找到下一个该执行的任务。

理清楚上面这些思路,就成功了一半了。既然回调函数的执行表示当前任务执行完毕,那么,我们就应该在回调函数中找到下一个该执行的任务

所以,我们的目的主要在于如何编写回调函数。

实现

function queue(list, count) {

    function next() { }

    for(let i = 0; i < count; i++) {
        list[i](next);
    }
}

实现到上面这一步很容易,我们将任务按照最大窗口数 count 同时执行。现在,我们要想办法找到下一个该执行的任务。

我们如何知道当前执行的任务是哪一个呢?下标

那么找到下一个任务就很容易了,那就是下一个下标。

function queue(list, count) {
    // 注意 1
    let index = count;

    function next() {
        // 注意 2
        list[index] && list[index++](next);
    }

    for(let i = 0; i < count; i++) {
        list[i](next);
    }
}

上面这段代码需要注意的地方有两点:

  1. index 的值取 count的原因,一开始会执行 count 个任务,所以下一个任务下标直接从 count 开始。
  2. 在这里要判断数组越界,当 list[index] 为有效值时再执行该函数。

总结

碰到这个问题时,我第一时间没有理清思路,根本没有考虑到回调函数的作用,所以没有写出来。思考问题时,要考虑到问题的核心是什么,目的是什么,这样才能思路清晰、事半功倍。