如何限制并发执行?

How to limit concurrent exectuions?

我要下载70张图片。它们的完整大小约为 100mb。

这是我简化的部分代码

function downloadImage(src){
    var dst = '...';
    request(src).pipe(fs.createWriteStream(dst));
    return dst;
}

arrayOf70.forEach(function(e){
    var thing = new Thing({
        // ...
        image: downloadImage(url)
    });
    thing.save();
}

问题是并发下载过多。好的第一步:传递一个巨大的超时请求。

request({url: src, timeout: 120000000}).pipe(fs.createWriteStream(dst));

好吧,由于它超过了 OS TCP 超时,所以效果不佳。至少我认为这是问题所在。不管怎样,我的连接超时了

stream.js:94
      throw er; // Unhandled stream error in pipe.
            ^
Error: connect ETIMEDOUT
    at exports._errnoException (util.js:746:11)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1000:19)

所以。限制并发下载量有什么办法?

这里有一个 setInterval 的例子:

var array_length = arrayOf70.length;
var i = 0;

var request_interval = setInterval(makeRequest, 100);

function makeRequest()
   if(i<array_length){
      var thing = new Thing({
         // ...
         image: downloadImage(url)
      });
      thing.save();
      i++;
   }else{
      clearInterval(request_interval);
   }
},100);

超时不是理想的解决方案。您真正需要的是等待下载完成然后立即开始新下载的能力。并表示特定次数的并行。 您可以使用回调来做到这一点。

function downloadImage(src, callback){
  var dst = '...';
  http.get(src, function(res) {
    res.pipe(fs.createWriteStream(dst))
      .on("finish", function() {
        callback(dst);
    });
  });
}    
function downloadAllImages(array) {
  var idx = 0;

  function downloadLoop() {
    if(idx >= array.length) return;
    downloadImage(array[idx++], function(dst) {
      var thing = new Thing({
          // ...
          image: dst
      });
      thing.save();
      downloadLoop();
    });
  }

  for(var i = 0; i < 5; i++) downloadLoop(); //start 5 concurrent download "loops"
}