面试官:如何实现一个并发控制?

在前端开发的面试中,关于如何控制并发的问题经常被提及。无论是处理网络请求、文件上传还是其他异步操作,有效地管理并发都是确保应用性能和用户体验的关键。本文将通过一个简单的例子来探讨如何使用JavaScript实现并发控制,并解释其中涉及的核心概念。

一. 问题的提出

想象这样一个场景:你需要同时发起多个网络请求,但出于对服务器负载或客户端性能的考虑,你希望限制同时进行的最大请求数量。例如,如果一次性发送过多的请求,可能会导致服务器过载,或者客户端资源耗尽,影响用户体验。因此,我们需要一种机制来控制并发执行的任务数量。假设每次只能允许两个请求发送,这两个请求完成后其他请求才能发送,我们要怎么实现呢?

思考过程

  • 为什么需要控制并发? 当我们有大量任务需要执行时(比如批量上传图片),如果不加以控制,所有任务会同时开始,这可能导致系统资源耗尽,响应变慢,甚至崩溃。
  • 目标是什么? 我们的目标是设计一个可以动态调整并发数的机制,使得我们可以控制任意时刻最多有多少个任务正在执行。

二. 设计思路

要想保证每次只能两个任务进行,那我们首先能想到哪种数据结构呢?当然是数组了,先存入两个要执行的任务,当这个数组里有任务完成后,再添加进新的任务。这样每次都保证数组里的两个任务执行,从而实现并发控制。

核心思考点

  1. 任务队列:我们需要一个地方来存放所有的待执行任务。这里我们可以使用数组作为我们的任务队列。
  2. 状态管理:我们需要跟踪当前正在运行的任务数量。可以通过一个计数器变量来实现这一点。
  3. 调度逻辑:当某个任务完成时,我们应该从队列中取出下一个任务并开始执行它。为了实现这一逻辑,我们需要监听任务完成的事件,并根据情况调用调度函数。

三. 实现难点

1. 监听任务完成

由于每个任务都是异步的(比如网络请求),我们需要知道什么时候这些任务完成了。JavaScript中的Promise对象提供了一种很好的方式来处理异步操作的结果。通过.then()方法,我们可以在任务成功完成时得到通知;通过.catch()方法,我们可以在任务失败时得到通知。

2. 动态调度任务

一旦我们知道了一个任务已经完成,我们就需要触发下一轮的任务调度。这意味着我们需要重新检查当前是否还有空闲的并发槽位,并从任务队列中取出新的任务来执行。

代码实现

js 复制代码
class Limit {
    constructor(paralleCount = 2) {
        this.tasks = [];
        this.runningCount = 0;
        this.paralleCount = paralleCount;
    }

    add(task) {
        return new Promise((resolve, reject) => {
            this.tasks.push({task, resolve, reject});
            this._run();
        });
    }

    _run() {
        while (this.runningCount < this.paralleCount && this.tasks.length) {
            const {task, resolve, reject} = this.tasks.shift();
            this.runningCount++;
            task().then(() => { // 一个任务完毕了
                resolve()
                this.runningCount--
                this._run()
            }).catch((err) => {
                reject(err)
                this.runningCount--
                this._run()
            })
        }
    }
}

const limit = new Limit(2);
function addTask(time, name) {
    limit.add(() => ajax(time))
         .then(() => console.log(`任务${name}完成`))
         .catch(() => console.log(`任务${name}出错`));
}

运行结果如下:

通过上述分析和实现,我们不仅解决了并发控制的问题,还深入理解了其背后的原理和设计思想。这种模式不仅可以应用于网络请求,还可以扩展到任何需要控制并发执行的任务场景中。

相关推荐
光影少年18 分钟前
es6+新增特性有哪些
前端·javascript·es6
GDAL32 分钟前
Better-SQLite3 参数绑定详解
javascript·sqlite3
猿榜39 分钟前
js逆向-某博博返回数据解密
javascript·python
IT、木易1 小时前
大白话解释 JavaScript 中的this关键字,它在不同场景下是如何取值的?
开发语言·javascript·ecmascript
前端涂涂1 小时前
JavaScript面试宝典
前端·javascript
潜龙在渊灬2 小时前
前端 UI 框架发展史
javascript·vue.js·react.js
写不出代码真君3 小时前
Proxy和defineProperty
前端·javascript
乐坏小陈3 小时前
TypeScript 和 JavaScript:2025 年应该选择哪一个?【转载】
前端·javascript
Clrove.113 小时前
JavaWeb——Ajax
前端·javascript·ajax
Epicurus3 小时前
DOM节点类型列举
前端·javascript