如何使用node.js获取图像URL数组并asynchronous保存到s3?

我正在上传图像url的数组保存到S3。 代码工作,但它不是asynchronous执行。 给控制台加上时间标记似乎表明,首先所有的图像都被提取和缓冲,然后它们被顺序保存到s3。 我跑了100张图片,第一张图片没有被提交到s3,直到第100张被提取。 至less看起来是这样的,因为我从图像请求callback中获取控制台中的时间戳stream,并且直到最后一次图像callback已经加了时间戳,“save to s3”时间戳才会启动。 我对节点相当陌生,经过两天的实验,我还没有破解这个。

我也试过直接pipe道,但是这需要所有的文件有内容长度设置,有些不会。 我原本只有一个函数getImageFromUrl,但是把它分解成三个单独的小函数来帮助我们找出问题所在。 我正在使用请求,knox for s3和async.each迭代器的caolanasynchronous库。 代码如下:

var images2get = req.body.images2get; // an array of image urls to be fetched and saved to s3 var startTime = (new Date()).getTime(); //iterate over the array and get each image, save to S3 var imageNumber = 0; // this needs to come before the iterator so it's defined async.each(images2get, getImageFromUrl, function(err){ if(err) { console.log('async each failed for images2get'); } else { res.send(200); } }); function getImageFromUrl(url2fetch, nextImage){ var options = {encoding: null, url: url2fetch, method: 'GET', timeout: 10*1000 } request(options, function(err, fetchResponse, body){ if(!err && fetchResponse && fetchResponse.statusCode == 200) { nextImage(); //we've got the image, call the iterator to fetch the next one var s3Config = prepareImageForS3(fetchResponse, url2fetch); saveToS3(body, s3Config); } else { //there was a problem fetching the url console.log('Error ' + fetchResponse.statusCode + ' Failed to get image from ', url2fetch.absolute); nextImage(); } }); }; function prepareImageForS3(fetchResponse, url2fetch) { console.log('preparing image ' + imageNumber + ' at ', (Date.now() - startTime)); imageNumber += 1; var filename = '/' + userId + '/' + pageId + '/image' + imageNumber; var headers = { 'Content-Type': fetchResponse.headers['content-type'], 'x-amz-acl': 'public-read' }; return{ 'filename': filename, 'filetype': 'image', 'filenumber': imageNumber, 'headers': headers, 'replaceSrc': true, 'url': url2fetch }; }; function saveToS3(file, s3Config) { s3Client.putBuffer(file, s3Config.filename, s3Config.headers, function(err, res){ console.log('image ' + imageNumber + ' submitting to s3 at ', (Date.now() - startTime)); //console.log('response from s3 save from url, status:', res.statusCode, 'url:', res.req.url); if(!err && res.statusCode === 200 && s3Config.replaceSrc) { console.log('image ' + imageNumber + ' saved to s3 at ', (Date.now() - startTime)); } else { console.log('failed to save image to S3 from ' + res.req.url) } }); }; 

你可以用你的代码改进几件事情:

  • HTTP代理

首先,node.js使用一个HTTP代理 ,它限制了一个主机的并发连接数量。 如果不是这样,你可能会不小心闯入成千上万的连接。

您可以通过将{agent: false}传递给请求来禁用它。 请注意,knox 已经禁用它 。

我怀疑这是你的代码顺序运行的原因。

  • Async.each

Async.each将并行运行所有迭代。 当你调用nextImage() ,你不会说asynchronous开始下一个迭代,而是说你已经完成了。 所有迭代完成后,asynchronous完成。 这里的问题是在你告诉asynchronous你完成之后继续工作。