许多排队操作的Q模式

我正在为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; 

真的,我需要做的就是排队所有的resize操作,并顺序运行它们,以便它不会同时打开所有的文件,但我不知道如何做到这一点。 这种事情有没有标准模式?

你可以做这样的事情:

 //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来链接promise以进行sorting。 这应该确保在转移到下一个图像之前处理一个图像。

把resize的过程分解成一个返回承诺的函数是比较容易的,但不是必须的。

这可以让你在主程序中看到树木。

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