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

在前端开发的面试中,关于如何控制并发的问题经常被提及。无论是处理网络请求、文件上传还是其他异步操作,有效地管理并发都是确保应用性能和用户体验的关键。本文将通过一个简单的例子来探讨如何使用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}出错`));
}

运行结果如下:

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

相关推荐
gaolei_eit1 小时前
Vue3项目ES6转ES5,兼容低版本的硬件设备,React也
javascript·react.js·es6
一位搞嵌入式的 genius1 小时前
从 ES6 到 ESNext:JavaScript 现代语法全解析(含编译工具与实战)
前端·javascript·ecmascript·es6
子兮曰7 小时前
OpenClaw架构揭秘:178k stars的个人AI助手如何用Gateway模式统一控制12+通讯频道
前端·javascript·github
百锦再8 小时前
Reactive编程入门:Project Reactor 深度指南
前端·javascript·python·react.js·django·前端框架·reactjs
百锦再8 小时前
React编程高级主题:测试代码
android·前端·javascript·react.js·前端框架·reactjs
颜酱9 小时前
图结构完全解析:从基础概念到遍历实现
javascript·后端·算法
小迷糊的学习记录10 小时前
Vuex 与 pinia
前端·javascript·vue.js
发现一只大呆瓜10 小时前
前端性能优化:图片懒加载的三种手写方案
前端·javascript·面试
不爱吃糖的程序媛10 小时前
Flutter 与 OpenHarmony 通信:Flutter Channel 使用指南
前端·javascript·flutter
利刃大大10 小时前
【Vue】Element-Plus快速入门 && Form && Card && Table && Tree && Dialog && Menu
前端·javascript·vue.js·element-plus