我有从代码中下载图片的代码。它遍历数据库中的产品,并为每个产品调用图像下载。
然而,一切似乎都是异步发生的,如果有太多的URL(要下载的图像),则进程会因TIMEOUT而停止。这是合乎逻辑的,因为有大约3000个图像要下载。
您能否给我一些建议如何改进代码,以便仅下载#34; 10"图像并且不会在之前的" 10"没做完? 我还不习惯node.js异步功能。
// download file
var download = function (uri, filename, callback) {
request.head(uri, function (err, res, body) {
request(uri).pipe(fs.createWriteStream(filename))
.on('error', () => {
console.log('Err');
})
.on('close', callback);
})
};
// main code - looping through products in DB and upload file for each product (about 3000 products)
knex("products").select("products.id as id", "products.img as img", "products.code as code")
.mapSeries(function (product) {
var imgName = 'imgs/' + product.code.toString() + ".png";
download(product.img, imgName, function () {
knex("products").where("id", product.id).update("img_path", imgName).then(() => {
});
});
}
})
.then(() => {
// console.log('done');
});
答案 0 :(得分:3)
使用async.eachOfLimit以便按批处理Y元素进行X异步操作:
var async = require("async");
// products retrieved from bdd
var products = [{img: "http://www.google.fr/a", code:"yolo", id:1}, {img: "https://www.google.fr/b", code:"yolo2", id:2}];
async.eachOfLimit(products, 10, function(currentproduct, key, ecb){
// function called for each products
var imgName = 'imgs/' + currentproduct.code.toString() + ".png";
download(currentproduct.img, imgName, function () {
knex("products").where("id", currentproduct.id).update("img_path", imgName).then(() => {
// call next
ecb(null);
});
});
}, function(err){
// final callback when all products has been proceed
if(err)
{
// do stg
}
else
{
console.log("yeah");
}
})
答案 1 :(得分:2)
我们有限制这些异步功能
mapLimit(coll, limit(number), iteratee, callback)
async.mapLimit(['file1','file2','file3'], fs.stat, function(err, results) {
// results is now an array of stats for each file
});
或
eachLimit(coll, limit(number), iteratee, callback)
所以这将解决您的要求,因为在任何给定时间只有限制并行呼叫数