javascript - 等待异步函数和其中的承诺完成
问题描述
我的任务:我有一个包含许多项目的文件,每个项目都与我需要下载的图像 URL 数组相关。我想下载所有链接,我正在使用这个库来下载图像,并且我正在使用 Promise。
问题: 当我开始从许多项目下载许多图像时出现问题,程序在第一个完成之前发送了 4000 多个请求并且程序崩溃了。
我的解决方案:我的想法是一次只处理大约 2 个项目,以便我一次下载大约 20 个图像。我已经尝试过各种带有 promises 和 async 函数的变体,但我对这些很陌生,所以我的尝试失败了。
我的代码流程是这样的:
csvRun()
function csvRun(){
for(let i = 1; i <= itemsAmount; i++){ // Loops over the items
// I want to be able to run only x items at a time
console.log('Item number ' + i)
itemHandle()
}
}
function itemHandle(){ // This function seems useless here but since the item has more data I kept it here
handleImages()
}
function handleImages(){ // Loops over the images of the item
for(let g = 0; g < imagesAmount; g++){
// Here there is a promise that downloads images
// For the example I'll use settimout
setTimeout(() => {
console.log('Image downloaded ' + g)
}, 3000);
/** If you want the error just use ImgDonwload instead of
settimeout and set imagesAmount to 20 and itemsAmount
to 400
*/
}
}
// Only here to recreate the error. Not necessarily relevant.
function ImgDownload(){
var download = require('image-downloader')
download // returns the promise so the handling could resume in order
.image({
url:
"https://cdn.vox-cdn.com/thumbor/XKPu8Ylce2Cq6yi_pgyLyw80vb4=/0x0:1920x1080/1200x800/filters:focal(807x387:1113x693)/cdn.vox-cdn.com/uploads/chorus_image/image/63380914/PIA16695_large.0.jpg",
dest: "/folder/img.jpg"
})
.then(({ filename, image }) => {
console.log("File saved to", filename);
})
.catch((err: Error) => {
console.error(err);
});
}
目前,代码完成循环csvRun
并在 3 秒Item number 1
后Item number {itemsAmount}
打印出所有Image downloaded messages
. 我明白为什么会这样。我想更改代码,以便每次只itemHandle
同时进行 2 个调用。
解决方案
一种选择是有一个循环遍历图像并一个接一个地处理。然后并行运行多个处理,启动多个循环:
// Goes over the "data" array, calls and waits for each "task" and processes "runnerCount" tasks in parallel
function inParallel(task, data, runnerCount) {
let i = 0, results = [];
async function runner() {
while(i < data.length) {
const pos = i++; // be aware: concurrent modification of i
const entry = data[pos];
results[pos] = await task(entry);
}
}
const runners = Array.from({ length: runnerCount }, runner);
return Promise.all(runners).then(() => results);
}
用作:
const delay = ms => new Promise(res => setTimeout(res, ms));
inParallel(async time => {
console.log(`Timer for ${time}ms starts`);
await delay(time);
console.log(`Timer for ${time}ms ends`);
}, [5000, 6000, 1000]/*ms*/, 2/*in parallel*/);
推荐阅读
- java - 如何将实时时间添加到 JPanel 以及按钮按下时间到其他 JPanel?
- java - 为什么这段代码会执行两条 println 语句,而不是一条一条打印?
- python - AttributeError:“dict”对象没有属性“forward”
- google-cloud-platform - GCLB 缺少 SameSite 和安全标志
- javascript - 没有递归地居中所有孩子的中心元素?
- r - R - 如何使用 ggplot2 对散点图的最大值和最小值点进行着色和标记?
- jmeter - 我在单线程中有多个登录 API,我需要从 CSV 文件中为每个 API 获取不同的值
- java - WebSphere:Spring Application 生成日志文件但未写入日志文件
- node.js - 应用户请求停止 multer 文件上传
- flutter - 如何将动画添加到“DropdownButtonFormField”(颤振)