如何基于JS实现Ajax并发请求的控制详解

编辑: admin 分类: javascript 发布时间: 2022-01-01 来源:互联网
目录
  • 前言
  • Ajax的串行与并行
  • Ajax的并发请求控制的两大解决方案
    • 基于Promise递归实现
    • 基于Class实现
  • 代码展示
    • 总结

      前言

      最近看到一个面试题,当然了,就是这篇文章的标题,Ajax的并发请求的控制,感觉挺有意思的,在社区看了下,应该是字节的面试题,也挺多大佬对这个进行了总结,都看了下,于是自己也想试着总结下,代码文末会全部贴出,如有不足,请指出!

      Ajax的串行与并行

      • 串行:一般业务需求是下个接口需要用到上个接口的返回的数据,前端常用的请求库是Axios,本身就是基于Promise的HTTP库,我们直接采用链式调用,或者采用Async Await 的方式就可以实现,就不做演示了
      • 并行:就是多个请求同时发生,一般情况会用于当所有数据都拿到后进行渲染页面,或者其他的操作,主要还是基于Promise.all实现方式如下

      上面模拟实现了基于Promise.all的并行操作,打印结果入下

      是不是觉得的这就结束了,不存在的?接下来才是正菜,我们试想有种情况,一个页面中需要同时发送上万个请求,全部成功后再去做一些操作,这样会导致什么后果呢?代码无法执行,内存溢出,哎~这个时候就回到了我们文章的主题上了,如何对Ajax并发请求的控制呢?我让他一次性只能输出一定数量的请求,直到所有的都成功为止,接下来我将用两种方法实现这个操作,望读者朋友们不吝赐教

      Ajax的并发请求控制的两大解决方案

      基于Promise递归实现

      以下的两种方法都是需要用到上图中的那个Tasks数组的,请大家记住它,第一中基于Promise的方法,大致思路是:当你传入一个并发量pool时,会创建pool个工作区,每一个工作区回去拿对应的任务(请求)去执行,成功后保存,然后继续去拿任务(请求),直到工作区没有任务了,当然了,失败直接终止, 大致思路就是这样,下面我对每一行代码进行了注释,请笑纳

      基于Class实现

      第二种方法是基于Class来实现的,和上面的区别在于这个只创造一个工作区,大致思路:创建一个工作区用于执行任务(请求),然后将所有任务都推入,但是没次只能执行对应的并发数,当小于并发数市,继续去拿任务执行它,直到没有任务(请求)为止, 就是这样,下面是具体实现

      代码展示

      这里把这两种方法的实现代码贴出

          const delay = function delay(interval【原URL http://www.yidunidc.com/jap.html 请说明出处】) {
            return new Promise((res,rej) => {
              setTimeout(() => {
                res(interval)
              }, interval);
            })
          }
      
      
          let tasks = [() => {
            return delay(1000)
          },() => {
            return delay(1003)
          },() => {
            return delay(1005)
          },() => {
            return delay(1002)
          },() => {
            return delay(1004)
          },() => {
            return delay(1006)
          }]
      
          // 通过Promise.all实现并行
          Promise.all(tasks.map(task => task())).then(res => {
            console.log(res);
          })
      
          // 基于Promise实现
      
          function creatRequest(tasks,pool) {
            // 每次控制的发送请求的数量pool
            pool = pool || 5
            // 用于存储每一次请求的结果(按顺序进行存贮)
            let results = [],
            // together 用于创建工作区,当pool传入的是几,我们就对应的创建几个工作区
            // 也就是创建一个长度为pool且值为null的一个数组
                together = new Array(pool).fill(null),
            // index为每次获取的任务值
                index = 0;
            together = together.map(() => {
              // 基于Promise进行管理
              return new Promise((resolve,reject) => {
                // 创建一个函数,进来立刻执行
                const run = function run() {
                  // 如果任务池已经空了,说明请求发送完成了,直接成功
                  if(index >= tasks.length) {
                    resolve()
                    return 
                  }
                  // 先将index保存一下用于存储当前成功请求的结果
                  let old_index = index,
                  // 获取当前发送的请求,然后把index进行累加,所以上面会把index保存起来
                  // 这里index++ 是先运算后累加的,而++index则相反,先累加后运算
                      task = tasks[index++];
                  // 执行请求
                  task().then(result => {
                  // 将成功结果保存
                    results[old_index] = result
                  // 递归继续执行,也就是继续拿到任务到工作区执行
                    run();
                  }).catch(reason => {
                    reject(reason)
                  })
                }
                // 立即执行
                run()
              })
            })
            // 用Promise.all管控工作区,也就是每次并发两个请求
            return Promise.all(together).then(() => results)
          }
      
      
          creatRequest(tasks,2).then(results => {
            // 都成功,整体才成功,按顺序存储结果
            console.log('成功',results);
          }).catch(resolve => {
            // 只要有一个失败,整体失败
            console.log('失败');
          })
      
      
      
          // 基于Class实现
          function creatRequest(tasks,pool,callback) {
            // 参数的限制与验证
            if(typeof pool === 'function') {
              callback = pool;
              pool = 5
            }
            if(typeof pool !== 'number') pool = 5
            if(typeof callback !== 'function') callback = function () {}
            // -------
            class TaskQueue {
              // 正在运行的个数
              runing = 0;
              // 将所有任务所存在的队列
              queue = [];
              // 存储执行任务(请求)的结果
              results = [];
              pushTask(task) {
                let self = this
                // 将任务推入工作区
                self.queue.push(task)
                // 执行发送请求的逻辑
                self.next()
              }
              next() {
                let self = this
                // 当正在执行的任务数小于并发量的时候继续去拿任务执行
                while(self.runing < pool && self.queue.length) {
                  self.runing++;
                  // 相当于拿一个任务删除一个任务
                  let task = self.queue.shift();
                  // 执行请求
                  task().then(result => {
                    // 将执行结果保存
                    self.results.push(result)
                  }).finally(() => {
                    // 将正在运行的个数清除
                    self.runing--
                    // 继续执行请求
                    self.next()
                  })
                }
                // 当没有任务了循环结束
                if(self.runing === 0) callback(self.results)
              }
      
      
            }
            // 实例化
            let TQ = new TaskQueue()
            tasks.forEach(task => TQ.pushTask(task))
          }
      
      
          creatRequest(tasks,2,results=> {
            console.log(results);
          })
      

      总结

      以上就是对这套面试题的总结了,也是自己做下记录,后续会不断的更新前端方面的文章,最后还是希望各位前端的小伙伴们都能坚持学习,技术不断提升,加油吧,骚年!!!

      到此这篇关于如何基于JS实现Ajax并发请求控制的文章就介绍到这了,更多相关JS实现Ajax并发请求控制内容请搜索hwidc以前的文章或继续浏览下面的相关文章希望大家以后多多支持hwidc!

      【本文来源:高防服务器 转载请保留连接】