本文深入解析Promise.all()的核心机制,说明其成功返回结果数组、失败返回首个reject值的特性。重点演示如何利用Promise.all结合递归回调实现并发请求限制功能,通过维护任务池控制同一时刻的最大请求数,确保异步操作有序执行且资源可控。
关于promise.all()的使用
Promise.all()方法用于将多个Promise实例封装为一个新的Promise实例。
需要注意的是,成功与失败的返回值存在差异:成功时返回一个包含所有结果的数组;而一旦有任何一个Promise进入reject状态,则立即返回最先被reject的那个状态值。
核心逻辑:将所有异步操作存入数组pros中,通过Promise.all(pros)来统一执行所有异步操作。
let pros = []
data.forEach(element => {
pros.push( this.getJsonFile(element.json,element.fileName) )
});
Promise.all(pros).then(val => {
this.fontsList = [...val]
})示例:
// 获取字体所有json文件展示
getIconFonts(isFresh) {
req.post(window.context.uc+`/system/file/v1/queryIconFiles`).then(rep => {
if(rep && rep.data) {
// 将所有异步操作存储到数组pros中
let pros = []
data.forEach(element => {
pros.push( this.getJsonFile(element.json,element.fileName) )
});
// 执行所有异步操作后处理数据
Promise.all(pros).then(val => {
this.fontsList = [...val]
this.uploadFonts = [...this.fontsList]
})
}
});
},
// 通过id获取json文件
getJsonFile(fileId, fileName) {
return new Promise((resolve, reject) => {
req.get(window.context.uc +'/system/file/v1/preview?fileId=' + fileId).then(rep => {
if(rep && rep.data) {
let data = {
fileName,
...rep.data
}
// 返回处理后的数据
resolve(data)
}
})
})
}利用Promise.all实现并发请求限制函数
Promise.all 的简单解释
// 当以下数组中promise1, promise2, promise3都resolve之后,触发promise.all的then函数。
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});需求解释
所谓并发请求,即有待请求接口100个,限制每次只能发出10个。即同一时刻最多有10个正在发送的请求。
每当10个之中有一个请求完成,则从待请求的接口中再取出一个发出。保证当前并发度仍旧为10。
直至最终请求完成。
设计思路
简单思路如下:(假设并发请求函数名字为limitedRequest)
- 设定一个数组(命名为:pool),用于后续Promise.all的使用
- 当limitedRequest被调用的时候,首先一次性发出10个请求,并放入到pool中
- 每一个请求完成后的回调函数中继续触发下一个请求,而下一个请求返回Promise,他的回调函数继续绑定同样的回调函数,即循环调用。(看不懂就直接看代码更易懂)
- 直到全部请求完成,停止。
代码实现
具体代码如下
// 模仿一个fetch的异步函数,返回promise
function mockFetch(param) {
return new Promise((resovle) => {
setTimeout(() => {
resovle(param);
}, 2000);
});
}
function limitedRequest(urls, maxNum) {
const pool = [];
// 处理maxNum比urls.length 还要大的情况。
const initSize = Math.min(urls.length, maxNum);
for (let i = 0; i < initSize; i++) {
// 一次性放入初始的个数
pool.push(run(urls.splice(0, 1)));
}
// r 代表promise完成的resolve回调函数
// r 函数无论什么样的结果都返回promise,来确保最终promise.all可以正确执行
function r() {
console.log('当前并发度:', pool.length);
if (urls.length === 0) {
console.log('并发请求已经全部发起');
return Promise.resolve();
}
return run(urls.splice(0, 1));
}
// 调用一次请求
function run(url) {
return mockFetch(url).then(r);
}
// 全部请求完成的回调
Promise.all(pool).then(() => {
console.log('请求已经全部结束');
});
}
// 函数调用
limitedRequest([1, 2, 3, 4, 5, 6, 7, 8], 3);# 最终返回结果 $ node .\src\views\doc\detail\index.js 当前并发度: 3 当前并发度: 3 当前并发度: 3 当前并发度: 3 当前并发度: 3 当前并发度: 3 并发请求已经全部发起 当前并发度: 3 并发请求已经全部发起 当前并发度: 3 并发请求已经全部发起 请求已经全部结束
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持本站。