Promise 控制并发请求数量

Promise 控制并发请求数量

前言:

浏览器对对同一个服务器的并发数是有限制的,参考如下表格(表格来源于网络,未进过严谨测试):

浏览器HTTP / 1.1HTTP / 1.0
IE 1166
IE 1066
IE 91010
IE 866
IE 6,724
火狐66
Safari 3,444
Chrome 4+66
歌剧 9.63,10.00alpha44
Opera 10.51+8
iPhone 24
iPhone 36
iPhone 44
iPhone 56
Android2-44

基于这个问题,加上多图上传的功能,就会出现 bug 了!!

如果接口请求超时时间为 5s,用户同时选择了 20-30 张图,每张图上传时间平均为 1s,并且图片用了分片上传

那就回得到,并发请求约等于 20,那么后面的请求就会被阻塞(注意只是阻塞,不过接口也在算时间了)。加上分片上传的逻辑,一张图片又被切为 3-4 个分片,再次分出 3-4 个请求~ 芜湖起飞

如果接口响应的慢,后面被阻塞的接口超过 5s 就就会被关闭,图片上传就被打断了,所以并发的请求不能给浏览器去帮我们挂起,而是要让我们自己控制

方案 1- async 和 await

这是最优雅的方案,代码量也少,上传图片只会上传完一张后在进行下一张,伪代码如下:

function uploadFn() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ success: 11 })
    }, 2000)
  })
}

async function upload() {
  var _upload = uploadFn
  let array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
  for (let index = 0; index < array.length; index++) {
    const element = array[index]
    console.log('循环开始')
    let res = await _upload.call(this)
    console.log(res, 'await结束')
  }
}

upload()

如果按上面的方式一次性拿到多张图,那倒问题不大,可是如果组件是重复调用,await 就控制不住了

upload()
upload()
upload()

所以还得从根源解决问题

limit-promise 并发请求控制

我也是看到一位大佬的博客,贴上他的 GitHub 仓库limit-promise

核心代码不长:

const LimitPromise = function(max) {
  this._max = max
  this._count = 0
  this._taskQueue = []
}

LimitPromise.prototype.call = function(caller, ...args) {
  return new Promise((resolve, reject) => {
    const task = this._createTask(caller, args, resolve, reject)
    if (this._count >= this._max) {
      // console.log('count >= max, push a task to queue')
      this._taskQueue.push(task)
    } else {
      task()
    }
  })
}

LimitPromise.prototype._createTask = function(caller, args, resolve, reject) {
  return () => {
    caller(...args)
      .then(resolve)
      .catch(reject)
      .finally(() => {
        this._count--
        if (this._taskQueue.length) {
          // console.log('a task run over, pop a task to run')
          let task = this._taskQueue.shift()
          task()
        } else {
          // console.log('task count = ', count)
        }
      })
    this._count++
    // console.log('task run , task count = ', count)
  }
}

if (typeof Promise.prototype.finally !== 'function') {
  Promise.prototype.finally = function(callback) {
    let P = this.constructor
    return this.then(
      value => P.resolve(callback()).then(() => value),
      reason =>
        P.resolve(callback()).then(() => {
          throw reason
        })
    )
  }
}

module.exports = LimitPromise

使用的时候

const LimitPromise = require('limit-promise')

// 引入自己写的请求的方法
const request = require('./request')

const MAX = 5

// 设置并发请求数量
const limitP = new LimitPromise(MAX)

// 重新封装一下请求的方法,最后都用 limitP 去发请求
function get(url, params) {
  return limitP.call(request.get, url, params)
}

function post(url, params) {
  return limitP.call(request.post, url, params)
}

module.exports = { get, post }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值