我正在为node.js编写一个小脚本,从文件中读取一堆图像名称(2.5k),调整图像大小并将它们输出到目录。我天真的方式导致文件句柄耗尽:
//get the list of images, one per line in the file
var imgs = file.split('\n');
//keep track of how many images we've processed
var done = imgs.length;
var deferred = Q.defer();
for (var i = 0; i < imgs.length; i++) {
(function resizeImg(img) {
//open the file for writing the resized image to
var stream = fs.createWriteStream('images/' + img);
stream
.on('open', function () {
//now that it's opened, resize the source image, and write it
//out to the stream
gm(img)
.resize(200, 200)
.write(stream, function (err) {
//we're finished writing - if there was an error, reject
//otherwise, we can resolve the promise if this was the last image
if (err)
deferred.reject(err);
else if (--done <= 0)
deferred.resolve();
});
});
})(imgs[i]);
}
return deferred.promise;
我真正需要做的是排队所有调整大小操作并按顺序运行它们,以便它不会同时打开所有文件,但我不知道如何做到这一点。这种事情有标准模式吗?
答案 0 :(得分:1)
你能做这样的事吗:
//get the list of images, one per line in the file
var imgs = file.split('\n');
//keep track of how many images we've processed
var done = imgs.length;
//Store an array of functions to be executed in sequence
var funcArr = [];
for (var i = 0; i < imgs.length; i++) {
//push a promise function onto the array
funcArr.push((function resizeImg(img) {
return function () {
var deferred = Q.defer();
//open the file for writing the resized image to
var stream = fs.createWriteStream('images/' + img);
stream
.on('open', function () {
//now that it's opened, resize the source image, and write it
//out to the stream
gm(img)
.resize(200, 200)
.write(stream, function (err) {
//we're finished writing - if there was an error, reject
//otherwise, we can resolve the promise if this was the last image
if (err)
deferred.reject(err);
else
deferred.resolve();
});
});
return deferred.promise;
}
})(imgs[i]));
}
//Sequences as described at http://documentup.com/kriskowal/q/
var result = Q();
funcArr.forEach(function (f) {
result = result.then(f, function (reason) {
//Default error handler for each image in the sequence that does a reject
});
});
//At this point result is a promise that will be resolved when all images have processed
return result;
for循环的每次迭代都会将一个返回promise的函数推送到funcArr数组中。在for循环之后使用Q将promises链接在一起进行排序。这应确保在移动到下一个图像之前处理一个图像。
答案 1 :(得分:0)
将调整大小过程分离为返回承诺的函数更容易,但不是必需的。
这使您可以在主程序中看到树木。
function resizeImages(file) {
//An inner utility function that returns a function that does the hard work and, importantly, that returns promise.
function resize(img) {
return function() {
var deferred = Q.defer(),
stream = fs.createWriteStream('images/' + img);
stream.on('open', function() {
gm(img).resize(200, 200).write(stream, deferred.resolve);//Always resolve, even if error is reported, thus allowing the .then chain to continue.
});
return deferred.promise;
}
}
var p = Q();//resolved starter promise
//main routine - build a .then chain
for(var imgs=file.split("\n"), i=0; i<imgs.length; i++) {
p = p.then(resize(imgs[i])).then(function(err) {
//Yup, we're handling reported errors in the success handler!
if(err) {
//Handle error here.
//throw(something) to stop the process or don't throw(anything) to continue.
}
});
};
return p;
}