[英]How to use Promise.all to handle thousands of request
在我的 React 应用程序中,我有一个组件可以将请求发送到最多可以处理 50 个请求的在线服务。 我现在收到一个执行 7000 个 MAC 的新请求。
function App() {
const [data, setData] = useState([]);
useEffect(() => {
const fetchData = async () => {
await axios.all([
axios.get("/ipdn/<MAC ADDRESS>", { timeout: 10000 }),
axios.get("/ipdn/<MAC ADDRESS>", { timeout: 10000 })
// Adding all the mac address .......
]).then((responseArr) => {
setData(responseArr)
});
};
fetchData();
}, []);
我想扩展 fetchData 函数,所以基本上它只会发送 50 个 IP 并等待迭代完成。
当迭代完成后,接下来的 50 次将被执行。
谢谢
这是没有任何外部库的情况下如何做到这一点:
const ips = [
/* List of mac address. */
];
useEffect(() => {
const fetchData = async () => {
const loadedData = [];
// Iterate over the slices of array until all the ips have been processed.
for (const sliceIps of sliceGenerator(ips)) {
const gettingData = sliceIps.map(getDataFromIp);
const sliceLoadedData = await axios.all(gettingData);
loadedData = loadedData.concat(sliceLoadedData);
}
setData(loadedData);
};
fetchData();
}, []);
const getDataFromIp = (ip) =>
axios.get("/ipdn/<MAC ADDRESS>", { timeout: 10000 });
// Generates a slice of an array, here the slice has a size of 50 max.
function* sliceGenerator(arr) {
const sliceSize = 50;
let i = 0;
while (i < arr.length) {
yield arr.splice(i, i + sliceSize);
i += sliceSize;
}
}
我在这里使用生成器function* sliceGenerator
来生成 ips 数组的切片。 通过这种方式,您可以 50 x 50 批量处理它们。
我也在使用for (... of ...)
循环。 这非常方便,因为您可以在里面使用await
关键字。
没有库,您可以使用此功能:
function poolPromises(iterPromises, poolSize) {
return new Promise((resolve, reject) => {
let promises = [];
function nextPromise() {
let { value, done } = iterPromises.next();
if (done) {
resolve(Promise.all(promises));
} else {
promises.push(value); // value is a promise
value.then(nextPromise, reject);
}
return !done;
}
while (promises.length < poolSize && nextPromise()) { }
});
}
此函数将从迭代器中获取承诺直至池大小。 每当承诺解决时,它将从迭代器中获取下一个承诺,以便池再次完成。 因此在生成下一个承诺块之前不必完全清空池。 一旦有空位,它就会被再次使用。
重要的是,迭代器仅在通过next()
方法从中提取时才创建下一个承诺。
在您的用例中,您可以按如下方式调用它:
const fetchData = async () => {
function * iterRequests() {
for (let macAddress of macAddresses) {
yield axios.get("/ipdn/" + macAddress, { timeout: 10000 });
}
}
return poolPromises(iterRequests(), 50).then(setData);
}
注意: fetchData
不必声明为async
,因为那里没有await
。
如果您在使用外部库时没有任何问题,您可以使用es6-promise-pool来管理并发请求,如下所示
import PromisePool from 'es6-promise-pool';
// macs - Array of mac addresses
useEffect(() => {
const fetchData = () => {
const results = [];
const generatePromises = function*() {
for (let count = 0; count < macs.length; count++) {
yield axios.get(`/ipdn/${macs[count]}`, ...);
}
}
const promiseIterator = generatePromises();
// Create a pool with 10 concurrent requests max
const pool = new PromisePool(
promiseIterator,
10 // Configurable
);
// To listen to result
pool.addEventListener('fulfilled', function (event) {
console.log('Fulfilled: ' + event.data.result);
results.push(event.data.result);
});
// Start the pool
pool.start().then(function () {
setData(results);
console.log('Complete');
});
};
fetchData();
}, []);
我对axios.all
不熟悉,那么我提供了一种使用Promise.all
。 我的想法是将输入数组拆分为每个block 50个地址,然后一一求解
function App() {
const [data, setData] = useState([]);
useEffect(() => {
// helper function, split array to chunked array
const splitToChunks = (items, chunkSize = 50) => {
const result = [];
for (let i = 0; i < items.length; i += chunkSize) {
result.push(items.slice(i, i + chunkSize));
}
return result;
}
const fetchData = async () => {
const result = []; // init value
const macAddresses = []; // array of mac addresses - your mac addresses
const chunkedArray = splitToChunks(macAddresses); // return array of array [[...50 mac adds], [], []]
for (const macs of chunkedArray) { // now macs is [...50 mac adds]
const promises = macs.map((mac) => {
return axios.get(`/ipdn/${mac}`, { timeout: 10000 });
});
// now promises is array contains 50 Promises
const response = await Promise.all(promises); // wait until finish 50 requests
result.push(...response); // copy response to result, and continue for next block
}
setData(result);
};
fetchData();
}, []);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.