当前位置:   article > 正文

前端axios并发控制器,拦截器,事件并发控制器_前端拦截器

前端拦截器

最初开发目的是做一个axios请求并发的控制功能。后来发现其他场景可能也有类似需要控制并发的需求,于是将此功能其抽离成公共的类,在需要的场景使用。

实现步骤

思考1:如何让一个事件处于等待执行的状态?立马想到的就是 Promise、async、await

思考2:需要记录哪些状态来实现?

        ①最大并发数量、②当前进行中的任务数量、③存储等待中的任务

思考3:每个事件执行前都要过安检 (自定义的interceptors方法),放行还是拦截,这是个问题!

思考4:放行下一个被拦截的任务。

结合1234:利用async、await和new Promise的resolve方法进行事件的执行控制。

        如果 最大并发数量>当前进行中的任务数量,则调用resolve方法,结束await等待。

        否则 将resolve方法存储到数组中,等待有任务完成后再从数组中提取并执行第一个resolve。

        直至 存储任务的数组为空。

并发拦截的类诞生

  1. // 并发拦截
  2. class ConcurrentInterceptors {
  3. constructor(maxProgressCount) {
  4. // 最大并发数量
  5. this.maxProgressCount = maxProgressCount;
  6. // 进行中的任务数量
  7. this.inProgressCount = 0;
  8. // 等待中的任务
  9. this.waitingArr = [];
  10. }
  11. /**
  12. * 拦截器
  13. * @return Promise.resolve()
  14. */
  15. interceptors = () => {
  16. return new Promise(resolve => {
  17. const { maxProgressCount, inProgressCount } = this
  18. // 非数字、isNaN、不大于0 不拦截
  19. if (typeof maxProgressCount !== 'number' || isNaN(maxProgressCount) || maxProgressCount <= 0) {
  20. resolve()
  21. return
  22. }
  23. // 当前进行的任务数量是否大于最大并发数量
  24. if (inProgressCount < maxProgressCount) {
  25. // 未超出数量
  26. this.inProgressCount += 1
  27. resolve()
  28. }else {
  29. // 超出数量
  30. this.waitingArr.push(resolve);
  31. }
  32. });
  33. }
  34. /**
  35. * 启动下一个被拦截的任务
  36. */
  37. next = () => {
  38. // 当前进行中的数量减一
  39. this.inProgressCount -= 1
  40. // 等待发送的请求的移除一个
  41. const nextResolve = this.waitingArr.shift();
  42. if(nextResolve){
  43. // 要进行下一个任务了 当前进行中的数量加一
  44. this.inProgressCount += 1
  45. nextResolve();
  46. }
  47. }
  48. /**
  49. * 更新最大并发数量
  50. * @param newMaxProgressCount
  51. */
  52. upMaxProgressCount = (newMaxProgressCount)=>{
  53. this.maxProgressCount = newMaxProgressCount;
  54. }
  55. }
  56. export default ConcurrentInterceptors

如何使用?示例①:在axios中使用

  1. import axios from 'axios';
  2. // 引入并发拦截器
  3. import ConcurrentInterceptors from './concurrentInterceptors';
  4. // 创建并发实例对象,并设置最大并发数量:2
  5. const concurrent = new ConcurrentInterceptors(2)
  6. // 创建axios实例对象
  7. const instance = axios.create({});
  8. // axios自身的请求拦截器
  9. instance.interceptors.request.use(
  10. async config => {
  11. /**
  12. * 关键代码
  13. * @description 并发拦截器启动 进行数量检测
  14. */
  15. await concurrent.interceptors()
  16. return config;
  17. },
  18. error => Promise.reject(error)
  19. );
  20. // axios自身的响应拦截器
  21. instance.interceptors.response.use(
  22. response => {
  23. /**
  24. * 关键代码
  25. * @description 通知并发拦截器有任务完成了 请放行下一个任务!
  26. */
  27. concurrent.next()
  28. return response;
  29. },
  30. error => {
  31. /**
  32. * 关键代码
  33. * @description 通知并发拦截器有任务完成了 请放行下一个任务!
  34. */
  35. concurrent.next()
  36. return Promise.reject(error);
  37. }
  38. );

以上并发的限制功能已经实现,可根据自己需求进行修改或直接使用。或者继续往下阅读。

结束?

还没!有新的问题:进行中的任务数量等待中的任务数据仅供内部方法使用,不能在类的外部修改。需要将类的属性私有化处理。于是有了优化版,修改为使用 WeakMap 的Class私有属性版本。使用方法同 示例① axios示例。

私有属性版本 (优化版)

  1. const privateWeakMap = new WeakMap();
  2. function getConcurrent(_this) {
  3. return privateWeakMap.get(_this)
  4. }
  5. class ConcurrentInterceptors {
  6. /**
  7. * 最大并发数量
  8. * @param maxProgressCount
  9. * @typeof number
  10. */
  11. constructor(maxProgressCount) {
  12. privateWeakMap.set(this,
  13. {
  14. // 最大并发数量
  15. _maxProgressCount: maxProgressCount,
  16. // 进行中的任务数量
  17. _inProgressCount: 0,
  18. // 等待中的任务
  19. _waitingArr: [],
  20. }
  21. );
  22. }
  23. /**
  24. * 拦截器
  25. * @return Promise.resolve()
  26. */
  27. interceptors = () => {
  28. const { _inProgressCount, _maxProgressCount } = getConcurrent(this)
  29. return new Promise(resolve => {
  30. // 非数字、isNaN、不大于0 不拦截
  31. if (typeof _maxProgressCount !== 'number' || isNaN(_maxProgressCount) || _maxProgressCount <= 0) {
  32. resolve()
  33. return
  34. }
  35. // 当前进行的任务数量是否大于最大并发数量
  36. if (_inProgressCount < _maxProgressCount) {
  37. // 未超出最大并发数量
  38. getConcurrent(this)._inProgressCount += 1
  39. resolve()
  40. } else {
  41. // 超出最大并发数量
  42. getConcurrent(this)._waitingArr.push(resolve);
  43. }
  44. });
  45. }
  46. /**
  47. * 启动下一个被拦截的任务
  48. */
  49. next = () => {
  50. // 当前进行中的数量减一
  51. getConcurrent(this)._inProgressCount -= 1
  52. // 等待发送的请求的移除一个
  53. const nextResolve = getConcurrent(this)._waitingArr.shift();
  54. if (nextResolve) {
  55. // 要进行下一个任务了 当前进行中的数量加一
  56. getConcurrent(this)._inProgressCount += 1
  57. nextResolve();
  58. }
  59. }
  60. /**
  61. * 更新最大并发数量
  62. * @param newMaxProgressCount
  63. */
  64. updateMaxProgressCount = (newMaxProgressCount) => {
  65. getConcurrent(this)._maxProgressCount = newMaxProgressCount;
  66. }
  67. /**
  68. * 获取_maxProgressCount属性值
  69. */
  70. get maxProgressCount() {
  71. return getConcurrent(this)._maxProgressCount
  72. }
  73. set maxProgressCount(newVal) {
  74. this.updateMaxProgressCount(newVal)
  75. }
  76. /**
  77. * 获取_sendAxiosIngCount属性值
  78. */
  79. get inProgressCount() {
  80. return getConcurrent(this)._inProgressCount
  81. }
  82. set inProgressCount(newVal) {
  83. throw new Error(`inProgressCount为只读属性`);
  84. }
  85. /**
  86. * 获取_awaitSendAxiosArr属性值
  87. */
  88. get waitingArr() {
  89. return getConcurrent(this)._waitingArr
  90. }
  91. set waitingArr(newVal) {
  92. throw new Error(`waitingArr为只读属性`);
  93. }
  94. }
  95. export default ConcurrentInterceptors

最后

1.还是不清楚如用使用?

将 ConcurrentInterceptors 类(第一个或者私有属性的都行)复制到 js文件,在需要的文件引入,并初始化实例对象

① 引入并发拦截器
import ConcurrentInterceptors from './concurrentInterceptors.js';
② 创建并发实例对象,并设置最大并发数量: num
const concurrent = new ConcurrentInterceptors(num)

如果不是axios则需要一个类似于axios公共拦截器一样的方法,并在此方法里调用 (见示例②)

③ 并发拦截器启动 进行数量检测
await concurrent.interceptors()

在每个事件执行完的方法 (见示例②)

④ 通知并发拦截器有任务完成了 执行下一个任务
concurrent.next() 

示例②

  1. import ConcurrentInterceptors from './concurrentInterceptors.js';
  2. // 最大并发数量设置为2
  3. const concurrent = new ConcurrentInterceptors(2)
  4. function fn1() {
  5.   // Do something
  6.   console.log('函数fn1');
  7.   // fn1执行完了,可以进行下一个任务了
  8.   concurrent.next()
  9. }
  10. function fn2() {
  11.   // Do something
  12.   console.log('函数fn2');
  13.   // fn2执行完了,可以进行下一个任务了
  14.   concurrent.next()
  15. }
  16. async function publicFn(type) {
  17.   // 并发拦截器启动 进行数量检测
  18.   await concurrent.interceptors();
  19.   // 等待执行
  20.   switch (type) {
  21.     case 'fn1':
  22.       fn1()
  23.       break;
  24.     case 'fn2':
  25.       fn2()
  26.       break;
  27.   }
  28. }

2.只能axios使用吗?

不是。任何需要控制并发的场景都可使用

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/104457
推荐阅读
相关标签
  

闽ICP备14008679号