在回调节点js上运行循环

时间:2015-06-08 15:20:01

标签: javascript node.js asynchronous

我需要调整一些图像的大小。问题是我使用的库每回调一次调整大小。

我想调整几张图片的大小,所以我把它放在一个循环中:

exports.resizeImages = function (req, res) {
    var images = fs.readdirSync('uploads/');

    for (var n = 0; n < files.length; n++) {
        var tgt = 'uploads/resized/' + images[n];

        gm(tgt).resize(150).write(tgt, function (err) {
            if (err) {
                console.log('resizing failed');
                res.status(400).send('failed to resize');
                return;
            }
            if (n == images.length) {

                res.status(200).send();
            }
        });
    }
}

我知道我不能这样做。我需要让循环等待,直到回调以某种方式响应。我已经看过一些例子,但我无法让它发挥作用。

有什么想法吗?

4 个答案:

答案 0 :(得分:1)

您也可以使用node async模块

这样的事情:

var async = require('async');

exports.resizeImages = function (req, res) {
    var images = fs.readdirSync('uploads/');

    async.each(images, function(file, callback) {
        var tgt = 'uploads/resized/' + file;
        gm(tgt).resize(150).write(tgt, callback);
    }, function(err) {
        if(err) {
            console.log('resizing failed');
            return res.status(400).send('failed to resize');
        } else {
            //no error
            return res.status(200).send();
        }
    });
}

答案 1 :(得分:0)

您需要使用promises编写for循环。选择你最喜欢的诺言库。详细信息包含在this questionthis question中。或者在此blog post

var Promise = require('bluebird');

var promiseWhile = function(condition, action) {
var resolver = Promise.defer();

var loop = function() {
    if (!condition()) return resolver.resolve();
    return Promise.cast(action())
        .then(loop)
        .catch(resolver.reject);
};

process.nextTick(loop);

return resolver.promise;

};

答案 2 :(得分:0)

事实上,承诺对此很有帮助。还有其他库将回调包装到这种抽象中,但由于Promises是标准的,所以只学习一件事情会更好。

如果你想保持裸露,可以使用外部计数器:

var images = fs.readdirSync('uploads/');
var processed = 0;

for (var n = 0; n < files.length; n++) {
    var tgt = 'uploads/resized/' + images[n];

    gm(tgt).resize(150).write(tgt, function (err) {
        if (err) {
            console.log('resizing failed');
            res.status(400).send('failed to resize');
            return;
        }
        processed++;
        if (processed == images.length) {
            res.status(200).send();
        }
    });
}

假设您只发送200 OK所有图像都已正确调整大小。

答案 3 :(得分:0)

就像其他人提到的那样你可以使用promises,但是如果你不想在你的项目中开始使用promises async.js就完全适合这种事情了。

您的代码使用async.js重写:

exports.resizeImages = function (req, res) {

    async.waterfall([
        function readImages_step(done) {
            readdir('uploads/', done);
        },
        function uploadImages_step(images, done) {
            async.each(images, function(image, cb) {
                var target = 'uploads/resized/' + image;

                gm(target).resize(150).write(target, cb);
            }, done);
        }
    ], function (err) {
        if (err) {
            console.log('resizing failed');
            return res.status(400).send('failed to resize');
        }
        return res.status(200).send();
    }
};

我将readdirsync调用更改为异步。 Async.each将并行运行每个上传。