Цепочка обещаний увеличивает время выполнения? - PullRequest
0 голосов
/ 03 мая 2020

Я создаю простую NODE-JS функцию, которая преобразует PDF в Image> Обрезать Image> Объединить их обратно с 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) должна завершиться sh в среднем в 1100-1500 мс (*), но затрачиваемое время составляет ~ 2500 мс.

* время в 1100-1500 мс достижимо при использовании цепочки функций, но это трудно читать и поддерживать для меня.

Я собираюсь использовать эту функцию в 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) }); 

Использование вышеуказанного шаблона не решило мои проблемы здесь.

1 Ответ

0 голосов
/ 03 мая 2020

Есть большая вероятность, что эта странность вызвана использованием файловой системы. Если я правильно понимаю, 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);
});

Затем дождитесь завершения, прежде чем решить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...