2

我正在上传要保存到 S3 的图像 url 数组。该代码有效,但它不是异步执行的。控制台的时间戳显示首先获取并缓冲所有图像,然后将它们顺序保存到 s3。我运行了一个包含 100 个图像的数组,直到第 100 个图像被提取后,第一个图像才提交给 s3。至少看起来是这样,因为我在控制台中从图像请求回调中获得了时间戳流,并且“保存到 s3”时间戳直到最后一个图像回调被加上时间戳才会开始。我对节点相当陌生,经过两天的实验,我还没有破解这个。

我也尝试过直接管道它,但这需要所有文件都设置内容长度,有些则不会。我最初将 getImageFromUrl 放在一个函数中,但将其分解为三个单独的较小函数,以帮助找出问题所在。我将 request、knox 用于 s3,并将 caolan 的异步库用于 async.each 迭代器。代码如下:

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)
        }    
    }); 
};
4

1 回答 1

0

您可以使用代码改进几件事:

  • HTTP 代理

首先,node.js 使用HTTP 代理,它限制了与主机的并发连接数。如果不是这样,您很容易意外地敲击具有数千个连接的网站。

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

我怀疑这就是您的代码按顺序运行的原因。

  • 异步每个

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

于 2013-06-13T05:31:00.817 回答