Nodejs bluebird promise fails while processing ima

2019-07-12 01:41发布

问题:

//Created a promise for each image size.
var promises = sizes.map(function (size) {
    return new Promise(function (resolve, reject) {
      var destinationDir = fileUtil.getAbsolutePathOfImage(destinationPath);
      fileUtil.createDirectoryIfNotExists(destinationDir);
      destinationDir += size.src;
      fileUtil.createDirectoryIfNotExists(destinationDir);
      //Resize the image.
      //console.log('imagefile : ' + JSON.stringify(imageFile));
      //console.log('destinationDir: ' + JSON.stringify(destinationDir));
//Called an imageUtil resize method to perform resize.
      imageUtil.resize(imageFile, destinationDir, size).then(data => {
        var fileName = destinationPath + size.src + '/' + data;
        resolve(imageUtil.createImageData(fileName, size.height, size.width));
      }).catch(err => {
        console.error(err);
        return reject(err);
      });
    });
  });

  Promise.all(promises)
    .then(savedImages => {
      console.log('saved Images are: ' + JSON.stringify(savedImages));
      return res.status(200).json(savedImages);
    }).catch(err => {
      console.log('i am here' + JSON.stringify(err.message));
      return res.status(400).json(JSON.stringify(err.message));
    });



---------------------Resize method of imageutil---------------

var Promise = require('bluebird'),
  gm = require('gm'),
  path = require('path'),
  fs = require('fs');

Promise.promisifyAll(gm.prototype);

module.exports = {

  resize(imageFile, destinationPath, size){
    if (!imageFile || !destinationPath || !size) {
      return;
    }
    return new Promise(function (resolve, reject) {
      // If we just passed callback directly, errors would be fatal
      var fileName = fileUtil.getFileName(imageFile);
      //console.log('sourceFile : ' + JSON.stringify(imageFile));
      //console.log('saveDirectory : ' + JSON.stringify(destinationPath));
      //console.log('fileName is :' + fileName);
      //Create a write stream.
      var writeStream = fs.createWriteStream(destinationPath + '/' + fileName);
      //console.log('Saving at location: ' + writeStream.path);
      gm(imageFile)
        .resize(size.width, size.height, '^')
        .gravity('Center')
        .crop(size.width, size.height)
        .writeAsync(writeStream.path, function (err) {
          if (err) {
            var error = 'Error while creating image of resolution : ' + size.width + 'x' + size.height + '.';
            console.error(JSON.stringify(error));
            return reject(new Error(error));
          }
        });
      resolve(fileName);
    });
  }

};

*It seems like everything went correct and it creates four image file which is corrupted and gave me error later on but request processed succesfully. Console output of my image processing are as follows:

saved Images are: [{"src":"/uploads/300/fhjXFLgqq59F91uFK_2h8GiS.jpg","height":"200","width":"300"},{"src":"/uploads/120/fhjXFLgqq59F91uFK_2h8GiS.jpg","height":"120","width":"120"},{"src":"/uploads/48/fhjXFLgqq59F91uFK_2h8GiS.jpg","height":"48","width":"48"}]

POST /api/upload/image/ 200 51.790 ms - 241 "Error while creating image of resolution : 120x120." "Error while creating image of resolution : 48x48." "Error while creating image of resolution : 300x200."*

回答1:

Since you are already using promisifyAll, you don't need to (and should not) use the Promise constructor. writeAsync already returns a promise - if you don't pass a callback, as that's the requirement for Bluebird being able to pass the callback itself in the right position.

You should be using

module.exports = {
  resize(imageFile, destinationPath, size){
    if (!imageFile || !destinationPath || !size) {
      return Promise.reject(new Error("missing arguments"));
    }
    var fileName = fileUtil.getFileName(imageFile);
    //console.log('sourceFile : ' + JSON.stringify(imageFile));
    //console.log('saveDirectory : ' + JSON.stringify(destinationPath));
    //console.log('fileName is :' + fileName);
    //Create a write stream.
    var writeStream = fs.createWriteStream(destinationPath + '/' + fileName);
    //console.log('Saving at location: ' + writeStream.path);
    var promise = gm(imageFile)
      .resize(size.width, size.height, '^')
      .gravity('Center')
      .crop(size.width, size.height)
      .writeAsync(writeStream.path);
    return promise.then(function() {
      return filename;
    }, function (err) {
      var error = 'Error while creating image of resolution : ' + size.width + 'x' + size.height + '.';
      console.error(error, err);
      throw new Error(error);
    });
  }
};

Similarly, you shouldn't use the Promise constructor antipattern in the call to resize - it already returns a promise:

var promises = sizes.map(function (size) {
  var destinationDir = fileUtil.getAbsolutePathOfImage(destinationPath);
  fileUtil.createDirectoryIfNotExists(destinationDir);
  destinationDir += size.src;
  fileUtil.createDirectoryIfNotExists(destinationDir);
  //Resize the image.
  //console.log('imagefile : ' + JSON.stringify(imageFile));
  //console.log('destinationDir: ' + JSON.stringify(destinationDir));
  return imageUtil.resize(imageFile, destinationDir, size)
//^^^^^^
  .then(data => {
    var fileName = destinationPath + size.src + '/' + data;
    return imageUtil.createImageData(fileName, size.height, size.width));
  }, err => {
    console.error(err);
    throw err;
  });
});