更新记录
v1.0.0(2023-12-04) 下载此版本
2023-12-04: 核心方案案例完成
平台兼容性
Vue2 | Vue3 |
---|---|
√ | √ |
App | 快应用 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节小程序 | QQ小程序 |
---|---|---|---|---|---|---|
HBuilderX 3.6.0 app-vue app-nvue | √ | √ | √ | √ | √ | √ |
钉钉小程序 | 快手小程序 | 飞书小程序 | 京东小程序 |
---|---|---|---|
√ | √ | √ | √ |
H5-Safari | Android Browser | 微信浏览器(Android) | QQ浏览器(Android) | Chrome | IE | Edge | Firefox | PC-Safari |
---|---|---|---|---|---|---|---|---|
√ | √ | √ | √ | √ | √ | √ | √ | √ |
批量请求案例(百条!)解决方案
- 通过Promise实现分批请求,并做好控制
-
- 离开页面时,取消未完成的请求任务,返回页面后,检测有无需要继续的任务,若有则继续执行剩余任务
-
- 每项请求均可自定义请求参数
核心代码:
- BatchHttp.js
// 注:这里的 httpRequest 请根据自己项目而定,比如我的项目是uniapp,里面的http请求是 uni.request,若你的项目是 axios 或者 ajax,那就根据它们来对 BatchHttp 中的某些部分 import httpRequest from './httpRequest.js'
/**
-
批量请求封装 */ export class BatchHttp {
/**
- 构造函数
- @param {Object} http - http请求对象(该http请求拦截器里切勿带有任何有关ui的功能,比如加载对话框、弹窗提示框之类),用于发起请求,该http请求对象必须满足:返回一个包含取消请求函数的对象,因为在 this.cancelAll() 函数中会使用到 */ constructor(http=httpRequest) { / @private @type {Object[]} 请求任务数组 */ this.resTasks = [] /* @private @type {Object} uni.request对象 / this.http = http / @private @type {boolean} 取消请求标志 */ this.canceled = false }
/**
- 将数组拆分成多个 size 长度的小数组
- 常用于批量处理控制并发等场景
- @param {Array} array - 需要拆分的数组
- @param {number} size - 每个小数组的长度
-
@returns {Array} - 拆分后的小数组组成的二维数组 */
chunk(array, size) {
const chunks = [] let index = 0
while(index < array.length) { chunks.push(array.slice(index, size + index)) index += size; }
return chunks }
/**
- 单个数据项请求
- @private
- @param {Object} reqOptions - 请求配置
- @param {Array<string[]>} reqItemKeys - 请求时需要从 items 的每一项中获取数据的 key,这是个二维数组,reqItemKeys[i][0] 是请求接口参数key,reqItemKeys[i][1]是从 items 每一项中获取值的key
- @param {Object} item - 数据项
- @returns {Promise} 请求Promise
*/
singleRequest(reqOptions, reqItemKeys, item) {
return new Promise((resolve, _reject) => { const options = { url: reqOptions.url, method: reqOptions.method || 'GET', // data: reqOptions.data, success: res => { resolve({sourceItem:item, res}) } } let query = reqOptions.data || {} // 若设置了 reqItemKeys ,则根据此参数设置请求参数 if (Array.isArray(reqItemKeys) && reqItemKeys.length>0) { reqItemKeys.forEach(keyAry => { query[keyAry[0]] = item[keyAry[1]] }) } options.data = query const task = this.http(options) this.resTasks.push(task) }) }
/**
- 批量请求控制
- @private
- @async
- @param {Object} options - 函数参数项
- @param {Array} options.items - 数据项数组
- @param {Object} options.reqOptions - 请求配置
- @param {Array<string[]>} options.reqItemKeys - 请求时需要从 items 的每一项中获取数据的 key,这是个二维数组,reqItemKeys[i][0] 是请求接口参数key,reqItemKeys[i][1]是从 items 每一项中获取值的key
- @param {number} [options.concurrentNum=10] - 并发数
- @param {Function} [options.chunkCallback] - 分块回调
-
@returns {Promise} */ async #batchRequest({items, reqOptions, reqItemKeys=[], concurrentNum = 10, chunkCallback=(ress)=>{}}) { const promiseArray = [] let data = [] const passFlagProp = this.passFlagProp if(!passFlagProp) { data = items } else { // 若设置独立 passFlagProp 值,则筛选出对应属性值为空的数据(避免每次都重复请求所有数据,实现“继续未完成的批量请求任务”) data = items.filter(d => !Object.hasOwnProperty.call(d, passFlagProp) || !d[passFlagProp]) } // -- if(data.length === 0) return
data.forEach(item => { const requestPromise = this.#singleRequest(reqOptions, reqItemKeys, item) promiseArray.push(requestPromise) })
const promiseChunks = this.#chunk(promiseArray, concurrentNum) // 切分成 n 个请求为一组
for (let ck of promiseChunks) { // 若当前处于取消请求状态,则直接跳出 if(this.canceled) break // 发起一组请求 const ckRess = await Promise.all(ck) // 控制并发数 chunkCallback(ckRess) // 每完成组请求,都进行回调 } }
/**
- 设置用于识别忽略数据项的字段名
- (借此参数可实现“继续上一次完成的批量请求”);
- 如:passFlagProp='url' 时,在执行 exec 时,会过滤掉 items['url'] 不为空的数据,借此可以实现“继续上一次完成的批量请求”,避免每次都重复所有请求
- @param {string} val */ setPassFlagProp(val) { this.passFlagProp = val }
/**
- 执行批量请求操作
- @param {Object} options - 函数参数项
- @param {Array} options.items - 数据项数组
- @param {Object} options.reqOptions - 请求配置
- @param {Array<string[]>} options.reqItemKeys - 请求时需要从 items 的每一项中获取数据的 key,这是个二维数组,reqItemKeys[i][0] 是请求接口参数key,reqItemKeys[i][1]是从 items 每一项中获取值的key
- @param {number} [options.concurrentNum=10] - 并发数
- @param {Function} [options.chunkCallback] - 分块回调 */ exec(options) { this.canceled = false this.#batchRequest(options) }
/**
- 取消所有请求任务 */ cancelAll() { this.canceled = true for(const task of this.resTasks) { task.abort() } this.resTasks = [] } }