前言

最近看到一个面试题,当然了,就是这篇文章的标题,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) {
      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并发请求控制内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

如何基于JS实现Ajax并发请求的控制详解的更多相关文章

  1. ios – 为自定义创建的串行异步队列设置优先级

    如何使用GCD为自定义创建的串行异步队列设置高优先级?如果是这样,什么是替代解决方案?解决方法您的队列仍然是串行的.它只会在高优先级全局并发后台队列的一个插槽中一次执行一项任务.一旦创建,串行队列就不能以任何方式“并发”.同样,如果您创建并发队列并将其设置为以串行队列为目标,则它实际上变为串行.这一切都在manpage中有所涉及.

  2. 应用程序关闭时的iOS任务

    我正在构建一个应用程序,通过ajax将文件上传到服务器.问题是用户很可能有时不会有互联网连接,并且客户希望在用户重新连接时安排ajax调用.这可能是用户在离线时安排文件上传并关闭应用程序.应用程序关闭时可以进行ajax调用吗?

  3. android – Phonegap本地构建 – jquery ajax错误:readystate 0 responsetext status 0 statustext error

    解决方法您是否在索引文件中包含了内容安全元标记?

  4. Ajax简单的异步交互及Ajax原生编写

    一提到异步交互大家就会说ajax,仿佛ajax这个技术已经成为了异步交互的代名词.那下面将研究ajax的核心对象

  5. Ajax跨域问题的解决办法汇总(推荐)

    本文给大家分享多种方法解决Ajax跨域问题,非常不错具有参考借鉴价值,感兴趣的朋友一起学习吧

  6. ajax编写简单的登录页面

    这篇文章主要为大家详细介绍了ajax编写简单登录页面的具体代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  7. ajax从JSP传递对象数组到后台的方法

    今天小编就为大家分享一篇ajax从JSP传递对象数组到后台的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  8. 解决ajax返回验证的时候总是弹出error错误的方法

    这篇文章主要介绍了解决ajax返回验证的时候总是弹出error错误的方法,感兴趣的小伙伴们可以参考一下

  9. 使用AJAX完成用户名是否存在异步校验

    这篇文章主要介绍了使用AJAX完成用户名是否存在异步校验的相关资料,需要的朋友可以参考下

  10. ajax实现无刷新省市县三级联动

    这篇文章主要为大家详细介绍了ajax实现无刷新省市县三级联动的相关资料,利用三层架构实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部