JavaScript并发请求

业务场景

某一天,产品小姐姐让前端老王实现一个批量更新列表数据的需求。老王窃喜,小儿科,后端提供一个更新的接口不就完事儿了。不料,一直配合默契的后端那个哥们儿,刚刚删库跑路了,所以,就把这个接口开发的任务交给了一个新来的开发小弟弟。这个小弟弟比较实诚,三下五除二的就搞定了。然后找到老王说,“王哥哈,这个更新列表的接口写好了,你需要多次调用这个接口。”

“ what?调用一次不行么?”
“不行,因为列表批量更新数据比较大,如果其中一个更新失败,会导致这一批的更新失败,客户会投诉咱们滴,所以需要分别更新哈。”
“ md,有点儿道理哈。”
突然,产品小姐姐,来了一句,“要尽可能高效的完成批量更新数据呀!,咱们的客户属于小白那种!”
然后,隔壁老王就屁颠屁颠的开始疯狂撸码中。

归纳转化

老王苦思冥想,吹了吹掉在桌子上的2根头发,然后喃喃道,原来如此!
N个请求,最大并发请求个数M(M <= N),要求尽可能多的每刻执行M个请求

实现原理

  1. 创建一个待请求队列池(N),创建一个正在请求队列(M)
  2. 正在请求队列中任意一个请求完成后,通过notify函数发布通知
    2.1 把请求结果存储在response中
    2.2 已发送请求个数加一
    2.3 如果已发送请求个数等于待请求队列总数,则所有请求发送完毕
  3. 外部调用者通过callback函数,拿到最终的结果集合

代码解析

/**
 * 并发请求
 * 需求:n个请求,最大并发请求个数m(m <= n),要求尽可能多的每刻执行m个请求。
 */
import { getPluginVersionList } from '../axios/api';

class RequestService {
  /**
   * 待请求队列池【N】
   */
  requestQueue = [];
  /**
   * 最大并发请求个数【M】
   */
  limit = 0;
  /**
   * 并发请求的结果集合
   */
  response = [];
  /**
   * 最大请求总数
   */
  maxRequestCount = 0;
  /**
   * 已发送的请求个数
   */
  sentRequestCount = 0;
  /**
   * 外部调用者回调函数
   */
  callback = null;

  constructor(limit, list) {
    this.limit = limit;
    this.requestQueue = this.getRequestQueue(list);
    this.maxRequestCount = this.requestQueue.length;
  }

  /**
   *批量发送请求
   * @param {Function} callback
   */
  sendRequest(callback) {
    this.callback = callback;
    // 正在请求队列
    for (let i = 0; i < this.limit; i++) {
      const request = this.requestQueue.shift();
      request(this.notify.bind(this));
    }
  }

  /** private method */
  addRequest() {
    const request = this.requestQueue.shift();
    if (request) {
      request(this.notify.bind(this));
    }
  }

  /** private method */
  notify(value) {
    this.sentRequestCount++;

    this.response.push(value);
    this.addRequest();

    if (this.sentRequestCount === this.maxRequestCount) {
      this.callback(this.response);
    }
  }

  /**
   * private method
   * 请求接口封装
   * @param {} param `请求接口参数`
   * @returns Function
   */
  request(param) {
    return function request(notify) {
      getPluginVersionList({ id: param }).then(res => {
        // 通知外部请求接口成功
        notify(res);
      });
    }
  }

  /**
   * private method
   * 待请求队列池
   * @param {Array} list `选中的列表数据`
   * @returns
   */
  getRequestQueue(list) {
    return list.map(item => this.request(item));
  }
}

// 使用举例:
// 假如选中表格中的列表数据250条,任意时刻最大并发请求个数为13;
// 选中的列表数据
const selectedList = Array.from({ length: 250 }, (v, k) => k + 1);
const limit = 13;

const requestService = new RequestService(limit, selectedList);
requestService.sendRequest(function callback(res) {
  console.log(res);
});

参考链接

并发请求图片截图一
截屏2021-11-06 下午4.59.35.png
截屏2021-11-06 下午4.59.17.png
截屏2021-11-06 下午4.58.07.png
截屏2021-11-06 下午4.55.38.png
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 对于我们所研发的网站,若网站的访问量非常大,那么我们必须考虑相关的并发访问问题,而并发问题是绝大部分的程序员头疼的...
    百年叔叔阅读 11,508评论 0 16
  • 本文从上下文Context、同步原语与锁、Channel、调度器四个方面介绍Go语言是如何实现并发的。本文绝大部分...
    彦帧阅读 1,715评论 1 3
  • Redis 客户端 客户端通信原理 客户端和服务器通过TCP 连接来进行数据交互, 服务器默认的端口号为6379 ...
    WEIJAVA阅读 862评论 0 9
  • 第一部分 Python基础篇(80题) 1、为什么学习Python? Python相对于其他编程语言有很多优点: ...
    清清子衿木子水心阅读 1,828评论 0 1
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 8,067评论 0 4

友情链接更多精彩内容