2015-06-08 4 views
0

Мне нужно изменить размер некоторых изображений. Проблема в том, что библиотека, которую я использую, выполняет одно изменение размера для обратного вызова.Запустить цикл над обратным вызовом, узел js

Я хочу, чтобы изменить размер нескольких изображений, так что я положил его в петлю:

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

Я знаю, что я не могу сделать это, как это. Мне нужно, чтобы цикл подождал, пока обратный вызов не ответит каким-то образом. Я видел несколько примеров, но я не могу заставить его работать.

Любые идеи?

+0

Вам нужно использовать Promises. – djechlin

+0

где «файлы»? – Alex

+0

Что вы хотите сделать, если только один из файлов не работает, вы по-прежнему отправляете 400? – thefourtheye

ответ

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(); 
     } 
    }); 
} 
0

Вам нужно написать цикл for, используя обещания. Выберите свою любимую библиотеку обещаний. Детали указаны в this question или this 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; 

};

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 если все изображения были правильно изменены.

0

Как уже упоминалось, вы можете использовать обещания, но если вы не хотите, чтобы начать использовать обещания в проекте 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 будет запускать каждую загрузку параллельно.

Смежные вопросы