循环范围从服务器下载图像后的Java语言延迟

问题描述 投票:0回答:5

我有1个数组,像这样的数千个链接图像

let imageList = ["http://img1.jpg", "http://img2.jpg", ...];

我想遍历imageList,并在增加索引20次(n次)后延迟,例如

for(let i = 0; i <= imageList.length; i+=20){
  // with i from 0 -> 20
  // do download image from server
  downloadImages(0,20) // [start, end]
  // delay 5s to prevent server timeout because request many times

  // with i from 20 -> 40
  // do download image from server
  downloadImages(20,40)

  // continue delay 5s

  // .... try to finish
}
javascript
5个回答
1
投票

尝试像这样的东西:

const imageList = ['***'];

downloadImages(imageList)
  .then(/* done */)
  .catch(/* error */);

async function downloadImages(images) {
  for(let i = 0; i + 20 <= imageList.length; i += 20){
    const n20images = imageList.slice(i, i + 20);

    await fetchImages(n20images);
    await delay(5);
  }
}

function fetchImages(images) {
  return Promise.all(
    images.map(image => /* fetch(image) or smth else */)
  )
}

function delay(seconds) {
  return new Promise(resolve => setTimeout(resolve, seconds * 1000))
}

1
投票

在这种情况下,我使用async / await,来自lodash的of和块。它将以20组为单位发出不淹没服务器的请求

let i = 0
const imageListChunks = _.chunk(imageList, 20)
for await (const chunk of imageListChunks){
    const chunkPromises = downloadImage(0 + i*20, 20 + i*20)
    const chunkResp = await Promise.all(chunkPromises)
    i = i + 1
}

如果需要更多的延迟来让服务器喘口气,可以添加setTimeout以及另一个等待时间以减慢它的速度


1
投票

您可以使用asyncsetTimeout来实现:

let downloadImage = async url => {
  console.log(`Downloading ${url}`);
  
  // Simulate a download delay
  return new Promise(r => setTimeout(r, 100 + Math.floor(Math.random() * 500)));
}

let downloadAllImages = async (imageUrls, chunkSize=20, delayMs=2000) => {
  
  for (let i = 0; i < imageUrls.length; i += chunkSize) {
    
    console.log(`Downloading chunk [${i}, ${i + 20 - 1}]`); 
    
    // This `chunk` is a subset of `imageUrls`: the ones to be downloaded next
    let chunk = imageUrls.slice(i, i + 20);
    
    // Call `downloadImage` on each item in the chunk; wait for all downloads to finish
    await Promise.all(chunk.map(url => downloadImage(url)));
    
    // Unless this is the last chunk, wait `delayMs` milliseconds before continuing
    // (Note: this step may be poor practice! See explanation at bottom of this answer)
    if ((i + chunkSize) < imageUrls.length) await new Promise(r => setTimeout(r, delayMs));
    
  }
  
};

// Create an array of example urls
let imageUrls = [ ...new Array(100) ].map((v, n) => `http://example.com/image${n}.jpg`);

// Call `downloadAllImages`
downloadAllImages(imageUrls)
   
  // Use `.then` to capture the moment when all images have finished downloading
  .then(() => console.log(`Finished downloading ${imageUrls.length} images!`));

注意,如果正确实现了downloadImage,以便它返回一个承诺,该承诺将在下载图像时解决该问题,最好的做法是放弃超时。超时是一种启发式方法,可确保一次不会运行太多请求,但是如果您对请求完成的时间有清晰的了解,则可以在开始下一批之前简单地等待一批请求完成。

(有一个更有效的设计可供考虑(供您进一步研究)。为了理解,让我们考虑一下这种当前方法的问题(我将其称为“批处理”方法)。在当前批次完成之前,批次方法无法开始新批次。假设有20张图片,其中1张图片在1毫秒内下载,其中18张图片在5毫秒内下载,但最终图片需要10秒钟以上的下载时间;即使该系统应该具有一次下载20张图像的带宽,但最终只花费一个请求就花费了整整10秒钟的时间。一种更有效的设计(我们可以将其称为“最大带宽方法”)将保持20个进行中请求的队列,并且每次这些请求中的一个完成新请求时,都会立即开始。想象一下,第一张图片在1毫秒内下载完毕;当它完成并且只有19个请求正在进行时,“最大带宽方法”可以立即开始一个新请求,而无需等待其他19个请求完成。


0
投票

设置一些偏移

let offset = 0

for (let i = offset; i <= imageList.length; i += 20) {
  downloadImage(offset, offset + 20) 
  offset += 20
}

0
投票

您可以使用modulus operator

let imageList = ["http://img1.jpg", "http://img2.jpg", ...];

for(let i = 0; i <= imageList.length; i++){
  if (i % n == 0) //n is number of images to start delay
  START_YOUR_DELAY_HERE
  downloadImage(20); //20 is number of images you want to download
}
© www.soinside.com 2019 - 2024. All rights reserved.