MST

星途 面试题库

面试题:JavaScript函数调用多样化场景下处理异步任务

在JavaScript中,结合函数调用多样化场景,设计一个异步任务管理系统。要求能实现任务的排队执行、并行执行(限制最大并行数量)以及任务优先级调度。请给出具体实现代码,并详细阐述每部分代码在函数调用多样化场景中的作用和原理。
40.8万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

实现代码

class Task {
    constructor(name, priority, fn) {
        this.name = name;
        this.priority = priority;
        this.fn = fn;
    }
}

class TaskManager {
    constructor(maxParallel) {
        this.maxParallel = maxParallel;
        this.queue = [];
        this.running = [];
    }

    addTask(task) {
        this.queue.push(task);
        this.queue.sort((a, b) => b.priority - a.priority);
        this._processQueue();
    }

    _processQueue() {
        while (this.running.length < this.maxParallel && this.queue.length > 0) {
            const task = this.queue.shift();
            this._runTask(task);
        }
    }

    _runTask(task) {
        this.running.push(task);
        task.fn()
           .then(() => {
                console.log(`Task ${task.name} completed`);
            })
           .catch((error) => {
                console.log(`Task ${task.name} failed: ${error}`);
            })
           .finally(() => {
                const index = this.running.indexOf(task);
                if (index!== -1) {
                    this.running.splice(index, 1);
                }
                this._processQueue();
            });
    }
}

代码作用和原理阐述

  1. Task
    • 作用:用于创建任务实例,每个任务实例包含任务名称 name、优先级 priority 和具体执行的异步函数 fn
    • 原理:通过构造函数接收三个参数,将其赋值给实例属性,方便在任务管理系统中对任务进行识别、排序和执行。
  2. TaskManager
    • 构造函数
      • 作用:初始化任务管理器,设置最大并行任务数 maxParallel,并初始化任务队列 queue 和正在运行的任务数组 running
      • 原理:接收 maxParallel 参数并赋值给实例属性,同时创建两个空数组用于后续管理任务。
    • addTask 方法
      • 作用:向任务队列中添加任务,并根据优先级对任务队列进行排序,然后尝试处理任务队列。
      • 原理:将传入的任务添加到 queue 数组,通过 sort 方法按照优先级从高到低排序。然后调用 _processQueue 方法尝试启动新任务。
    • _processQueue 方法
      • 作用:检查正在运行的任务数量是否小于最大并行数且任务队列中还有任务,如果满足条件则从任务队列中取出优先级最高的任务并执行。
      • 原理:使用 while 循环不断检查 running 数组长度和 queue 数组长度,满足条件时取出任务并调用 _runTask 方法执行任务。
    • _runTask 方法
      • 作用:执行单个任务,将任务添加到正在运行的任务数组中,执行异步函数,处理任务完成、失败和最终清理操作。
      • 原理:先将任务添加到 running 数组,然后执行任务的异步函数 fn。通过 then 处理任务成功的情况,catch 处理任务失败的情况,finally 处理任务无论成功或失败都要执行的清理操作,即从 running 数组中移除任务,并再次调用 _processQueue 方法尝试启动新任务。

使用示例

// 创建任务管理器,设置最大并行数为 2
const manager = new TaskManager(2);

// 创建任务
const task1 = new Task('Task1', 2, () => new Promise((resolve) => {
    setTimeout(() => {
        console.log('Task1 running');
        resolve();
    }, 1000);
}));

const task2 = new Task('Task2', 1, () => new Promise((resolve) => {
    setTimeout(() => {
        console.log('Task2 running');
        resolve();
    }, 2000);
}));

const task3 = new Task('Task3', 3, () => new Promise((resolve) => {
    setTimeout(() => {
        console.log('Task3 running');
        resolve();
    }, 1500);
}));

// 添加任务
manager.addTask(task1);
manager.addTask(task2);
manager.addTask(task3);

在上述使用示例中,我们创建了一个最大并行数为 2 的任务管理器,并添加了三个具有不同优先级的任务。任务会按照优先级顺序和并行限制进行执行。