首页 > 解决方案 > 承诺链接导致执行时间增加?

问题描述

我正在创建一个简单的NODE-JS函数,将其转换PDFImage> Crops Image> Merge Them back with ImageMagick

这是我正在使用的完整代码:

var os = require('os');
var fs = require('fs');
var path = require('path');
var gs = require('node-gs');
var sharp = require('sharp');
var areaMap = require('./areaMap');
const { performance } = require('perf_hooks');
var spawn = require('child_process').spawnSync;
var pExcep = 'someException';

var gsPath = 'Ghostscript/gs26';
var src = path.join(os.tmpdir(), '/');

var Files = {
  file1: path.join(src, 'out1.jpeg'),
  file2: path.join(src, 'out2.jpeg'),
  OutImg: path.join(src, 'out.jpeg')
}

var crop = function (s, sFile) {
  return new Promise((res, rej) => {
    s = areaMap[s];
    sharp(Files.OutImg).extract(s)
      .toFile(sFile)
      .then(()=> res())
      .catch((err) => rej(err));
  });
};

var getBaseCard = function (s) {
  if (RegExp('^([0-9]{8})$').test(s)) { return 'SOMETHINGHERE' } else { return 'inception'; }
  //This can be done on client side.
}

var GetCardType = function (base, sInfo) {
  return new Promise((res, rej) => {
    if (base === 'SOEMTHINGHERE') {
      if (sInfo.includes('SOMETHINGHERE2')) {
        if (sInfo.includes(pExcep)) {
          res('PA_S_')
        } else {
          res('PA_S2')
        }
      } else {
        res('PA_ST')
      }
    } else {
      res('SA_')
    }
  })
}

var PdfToText = function (file, pass) {
  return new Promise((res, rej) => {
    gs()
      .batch().safer().nopause().res(2).option('-dDEVICEWIDTHPOINTS=20').option('-dDEVICEHEIGHTPOINTS=20').option('-dFIXEDMEDIA').option('-sPDFPassword=' + pass).device('txtwrite').output('-').input(file).executablePath(gsPath)
      .exec((err, stdout, stderr) => {
        if (!err) {
          res(stdout);
        } else {
          console.log(stdout);
          console.log(err);
          console.log(stderr);
        }
      })
  });
}

var getBaseImage = function (file, pass, quality) {
  return new Promise((res, rej) => {
    gs()
      .batch().nopause().safer().res(300 * quality).option('-dTextAlphaBits=4').option('-dGraphicsAlphaBits=4').option('-sPDFPassword=' + pass)
      .executablePath(gsPath).device('jpeg').output(Files.OutImg).input(file)
      .exec((err, stdout, stderr) => {
        if (!err) { res(); } else { rej(stdout) };
      })
  })
}

exports.processCard = function (file, password, quality) {
  return new Promise((resolve, reject) => {
    getBaseImage(file, password, quality) // Convert PDF to Image
      .then(() => {
        PdfToText(file, password) // Extract Text from pdf
          .then((res) => {
            GetCardType(getBaseCard(password), res) // finally get PDF Type
              .then((ct) => {
                // crop image here using Sharp
                Promise.all([ 
                  crop(ct + 'A_' + quality, Files.file1),  
                  crop(ct + 'B_' + quality, Files.file2)])
                  .then(() => {
                    // Merge Above two image into one using ImageMagick convert
                    spawn('convert', [Files.file1, Files.file2, '+append', 'files/out1.jpg']);
                    fs.unlinkSync(Files.OutImg); // Unlink tmp folders
                    fs.unlinkSync(Files.file1);
                    fs.unlinkSync(Files.file2);
                    resolve(); // finally resolve
                  }).catch((err) => reject(err));
              }).catch((err) => reject(err))
          }).catch((err) => reject(err))
      }).catch((err) => reject(err))
  })
} 

现在这些是我面临的问题:

 1. ImageMagick isn't creating the output file.
 2. fs.unlinksysnc throws ENOENT: no such file or directory, unlink '/tmp/out1.jpeg' 
    on average every second execution.

 3. Using above code increases execution time.
    For Example: getBaseImage should complete in 600ms but it takes 1400 using above code.

关于速度,它(Function不只是完整getBaseImage的)平均应在 1100-1500 毫秒(*)内完成,但所需时间约为 2500 毫秒。

* 1100-1500ms 的时间可以通过使用函数链接来实现,但这对我来说很难阅读和维护。

我将在Firebase Functions.

如何正确链接这些功能?

编辑

exports.processCard = function (file, password, quality) {
  return new Promise((resolve, reject) => {
    console.log(performance.now());
    getBaseImage(file, password, quality) //Convert PDF TO IMAGE
      .then(() => { return PdfToText(file, password) })
      .then((res) => {return GetCardType(getBaseCard(password), res) })
      .then((ct) => {
        return Promise.all([
          crop(ct + 'A_' + quality, Files.file1),
          crop(ct + 'B_' + quality, Files.file2)])
      })
      .then(() => {
        spawn('convert', [Files.file1, Files.file2, '+append', 'files/out1.jpg']);
        fs.unlinkSync(Files.OutImg); // Unlink tmp folders
        fs.unlinkSync(Files.file1);
        fs.unlinkSync(Files.file2);
        resolve();
      })
      .catch((err) => { console.log(err) }); 

使用上述模式并没有解决我的问题。

标签: javascriptnode.jspromiseimagemagick

解决方案


这种奇怪现象很可能是由使用文件系统引起的。如果我理解正确的话,云函数中的 fs 是在内存中的,所以当你写入它、读取它并从中删除时,你使用的操作系统内存越来越少。如果重复调用一个函数并重新使用加载的模块,那会变得很奇怪。

尝试为每次调用保持状态清洁的一件事是将所有内容(包括要求)放在处理程序的范围内。这样您就可以在每次调用时重新实例化所有内容。

最后,您似乎不需要等待生成的转换命令运行,您需要等待它完成:

const convertProc = spawn('convert', [Files.file1, Files.file2, '+append', 'files/out1.jpg']);
convertProc.on('close', function() {
 fs.unlinkSync(Files.OutImg); // Unlink tmp folders
 fs.unlinkSync(Files.file1);
 fs.unlinkSync(Files.file2);
 resolve();
})
convertProc.on('close', function(error) {
  reject(error);
});

然后在解决之前等待它完成。


推荐阅读