在 Node.js 中执行大量 http 请求的最佳方法是什么?



假设有一家商店有500种产品,每个产品的ID从0到500,每个产品都将其数据存储在URL下的JSON文件中(例如myshop.com/1.json...2.json等(。

使用Node.js脚本,我想下载所有这些JSON文件并将它们存储在本地。我可以连续做:

const totalProductsCount = 500;
try {
let currentItem = 1;
while (currentItem < (totalProductsCount + 1)) {
const product = await axios.get(`https://myshop.com/${currentItem}.json`);
fs.writeFileSync(`./product-${currentItem}.json`, JSON.stringify(product.data, null, 2));
currentItem++;
}
} catch (e) {
return;
}

这是有效的。不过,我想下载这些文件快,真的很快。因此,我试图将我的所有请求分成多个组,并将这些组并行。我有以下内容:

const _ = require('lodash');
const fs = require('fs');
const axios = require('axios');
const getChunk = async (chunk, index) => {
// The counter here is used for logging purposes only
let currentItem = 1;
try {
// Iterate through the items 1-50 
await chunk.reduce(async (promise, productId) => {
await promise;
const product = await axios.get(`https://myshop.com/${productId}`);
if (product && product.data) {
console.log('Got product', currentItem, 'from chunk', index);
fs.writeFileSync(`./product-${productId}.json`, JSON.stringify(product.data, null, 2));
}
currentItem++;
}, Promise.resolve());
} catch (e) {
throw e;
}
}
const getProducts = async () => {
const totalProductsCount = 500;
// Create an array of 500 elements => [1, 2, 3, 4, ..., 499, 500]
const productIds = Array.from({ length: totalProductsCount }, (_, i) => i + 1);
// Using lodash, I am chunking that array into 10 groups of 50 each
const chunkBy = Math.ceil(productIds.length / 10);
const chunked = _.chunk(productIds, chunkBy);
// Run the `getChunkProducts` on each of the chunks in parallel
const products = await Promise.all([
...chunked.map((chunk, index) => getChunk(chunk, index))
])
// If the items are to be returned here, it should be with a single-level array
return _.flatten(products);
};
(async () => {
const products = await getProducts();
})()

这似乎在大多数时候都有效,尤其是当我在少量项目上使用时。然而,有一种行为我无法解释,当我要求更多的物品时,脚本会挂起。

实现这一/最佳实践的最佳方法是什么,以及能够捕获任何挂起或可能尚未下载的文件(因为我的想法是,我可以通过分块操作下载任何我能下载的文件,然后取回所有未能下载的产品ID的数组,并使用第一种方法连续下载它们(。

您正在异步操作中同步写入文件!将writeFileSync更改为使用异步版本。这应该是一个立竿见影的改进。作为一种额外的性能增强,如果您希望将结果直接写入文件,那么理想情况下,您可以使用不解析响应的代码路径。看起来您可以在请求配置中使用responseType:'stream'来实现这一点。这将避免在将响应写入文件之前将其解析为JS对象的开销。

听起来,您可能还想将http请求的超时调整为较低级别,以确定几秒钟后是否会失败,而不是等待您认为应该失败的请求。如果您参考文档,请求配置中有一个参数,您可以将其降低到几秒钟。https://axios-http.com/docs/req_config

最新更新