Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript pdfMake管道上的节点内存不足_Javascript_Node.js - Fatal编程技术网

Javascript pdfMake管道上的节点内存不足

Javascript pdfMake管道上的节点内存不足,javascript,node.js,Javascript,Node.js,我有一个Nodejs服务器,用于创建大约1200个pdf表单,稍后客户端可以下载这些表单。它们是使用pdfmake创建的,然后输出到服务器文件夹。当我执行大约350个文档编写的代码时,Nodejs内存不足。我知道一定有更好的储蓄方式,但我似乎想不出来 Mongoose查询中的数据数组映射正在调用下面的方法。创建和保存表单的相关代码如下: const whichForm = certList => { certList.map(cert => { if (ce

我有一个Nodejs服务器,用于创建大约1200个pdf表单,稍后客户端可以下载这些表单。它们是使用pdfmake创建的,然后输出到服务器文件夹。当我执行大约350个文档编写的代码时,Nodejs内存不足。我知道一定有更好的储蓄方式,但我似乎想不出来

Mongoose查询中的数据数组映射正在调用下面的方法。创建和保存表单的相关代码如下:

const whichForm = certList => {
    certList.map(cert => { 
        if (cert.Cert_Details !== null) {
            switch (cert.GWMA) {
              case 'OA':
              case 'PC':
              // Don't provide reports for Feedlots
                if (cert.Cert_Details.cert_type !== null) {
                   if (cert.Cert_Details.cert_type === 'Irrigation') {
                     createOAReport(cert);
                   }
                }
                break;
             case 'FA':
             // Don't provide reports for Feedlots
               if (cert.Cert_Details.cert_type === 'Irrigation') {
                    createFAReport(cert);
                   }
               break;
               }
         }
    }
}
不同的文件:

const PdfPrinter = require('pdfmake/src/printer');
const fs = require('fs');

const createOAReport = data => {
    console.log('PC or OA Cert ', data.Cert_ID);
    // console.log(data);

    let all_meters_maint = [];

    data.Flowmeters.map(flowmeter => {
     // Each Flow meter
     // console.log(`Inside Flowmeter ${flowmeter}`);

      if (flowmeter.Active === true) {
        let fm_maint = [];
        fm_maint.push({
        text: `Meter Serial Number: ${flowmeter.Meter_Details.Serial_num}`
        });
      fm_maint.push({
        text: `Type of Meter: ${flowmeter.Meter_Details.Manufacturer}`
      });
      fm_maint.push({ text: `Units: ${flowmeter.Meter_Details.units}`});
      fm_maint.push({ text: `Factor: ${flowmeter.Meter_Details.factor}`});
      all_meters_maint.push(fm_maint);
    }

    docDefinition.content.push({
      style: 'tableExample',
      table: {
        widths: [200, 200, '*', '*'],
        body: all_meters_maint
      },
      layout: 'noBorders'
    });

    const fonts = {
      Roboto: {
        normal: path.join(__dirname, '../', '/fonts/Roboto- 
        Regular.ttf'),
        bold: path.join(__dirname, '../', '/fonts/Roboto-Medium.ttf'),
        italics: path.join(__dirname, '../', '/fonts/Roboto-Italic.ttf'),
        bolditalics: path.join(__dirname, '../', '/fonts/Roboto- 
        MediumItalic.ttf')
        }
    };

  const printer = new PdfPrinter(fonts);
  const pdfDoc = printer.createPdfKitDocument(docDefinition);

  // Build file path
  const fullfilePath = path.join(
    __dirname,
    '../',
    '/public/pdffiles/',
    `${data.Cert_ID}.pdf`
  );

  pdfDoc.pipe(fs.createWriteStream(fullfilePath));
  pdfDoc.end();
};

有没有一种不同的方法来保存文件,而不强制将其保存在流中,也不会保存在内存中?

在我们得到答案之前,我根据问题中的信息做了一个巨大的假设。问题是创建大约1200个pdf表单。这意味着我假设在函数中,参数certList的形式是一个1200项的数组。或者我应该说1200项将调用createOAReport方法。你明白了。我假设问题是我们调用该方法在Array.map方法中创建PDF 1200次。考虑到代码的问题和上下文,我相信这是有道理的

我想知道答案。主要的问题是,你不只是试图创建1200个PDF。您正在尝试异步创建1200个PDF,这当然会给试图同时完成所有这些工作的系统带来压力。在Node.js这样的单线程系统上可能更是如此

简单的黑客解决方案就是增加Node.js的内存。通过在运行node命令时使用-max old space size标志并以MB为单位设置内存大小。有关这方面的更多信息,请访问。但是短版本是一个类似node-max old space size=8192 main.js的命令。这将使Node.js的内存大小增加到8192MB或8GB

这种方法没有什么问题。主要是它不是超级可扩展的。如果有一天你想创建5000个PDF呢?您必须再次增加内存大小。可能会增加机器的规格

第二个解决方案,您实际上可能可以使用第一个解决方案,是使这个过程不是异步的。取决于许多因素以及当前系统的优化程度,这可能会增加创建所有这些PDF所需的时间

这个过程需要两个步骤来编码。首先是设置createOAReport函数,以返回一个承诺来指示何时完成。第二步是更改whichForm函数,以限制在任何单个时间点可以异步运行的项目数

当然,您必须对系统进行调整,以确定在不使系统过载的情况下一次要运行多少项。微调这个数字并不是我关注的重点,当然,您也可以通过增加Node.js的内存来增加这个数字

当然,有很多不同的方法可以做到这一点。我有一些方法的想法,这些方法比我将在这里展示的方法要好,但要复杂得多。限制同时运行的项目数量的基本思想仍然是相同的。您可以优化它以满足您的需要

我以前开发过这样的系统,但我不认为我这样做是最好或最干净的方式。但在这个问题的最后,我为您的示例附上了一些示例代码,试图说明我的观点

在深入了解这个答案之后,我才意识到我最初的假设是错误的。因为其中一些PDF可能是在第二个函数和data.Flowmeters.map系统中创建的。所以,尽管我不打算演示它,但你也必须将我在整个答案中给出的相同想法应用到该系统中。现在,我已经删除了该部分,并且只使用该数组中的第一项,因为它只是一个示例

一旦您了解了这一点,您可能希望重新构造代码,并且只使用一个函数来处理创建PDF的操作,而不需要到处调用那么多.map方法。将.map方法抽象出来,并将其与PDF创建过程分开。这样就更容易限制一次创建的PDF数量

在所有这些过程中添加一些错误处理也是一个好主意


注意,我实际上根本没有测试这段代码,所以可能有一些bug。但总体思路和原则仍然适用。

您的代码格式非常糟糕。请改进格式和样式,以便我们更容易帮助您。你的代码中还有很多未知的东西。如何调用此方法?数据等于什么?您在哪里定义所有仪表维护?等等。我更新了代码并添加了更多的上下文,希望能得到更多的帮助。太棒了!记住,越有效
如果你写一个高质量的问题,你会得到更好的答案。在您的代码中仍然有许多语法错误丢失}和,等等。。我想我修正了我答案示例中的所有问题。希望能有帮助!真棒的回答,我真的很感谢你的帮助,你的假设在代码和信息数组的执行中是正确的。我已经更改了节点的最大内存以允许增加的大小,但这是在处理问题的症状,而不是解决问题。我会采纳你的建议,并承诺在实施过程中尽量限制,并从那里开始@当然是希思!这是我在这个网站上写的一个更好的答案。所以我很高兴这对你有帮助。
const _ = require('lodash');

const MAX_RUNNING_PROMISES = 10; // You will have to play with this number to get it right for your needs

const whichForm = async certList => {
    // If certList is ["a", "b", "c", "d"]
    // And we run the following function with MAX_RUNNING_PROMISES = 2
    // array would equal [["a", "b"], ["c", "d"]]
    certList = _.chunk(certList, MAX_RUNNING_PROMISES);
    // Of course you can use something other than Lodash here, but I chose it because it's the first thing that came to mind

    for (let i = 0; i < certList.length; i++) {     
        const certArray = certList[i];

        // The following line will wait until all the promises have been resolved or completed before moving on
        await Promise.all(certArray.map(cert => {
            if (cert.Cert_Details !== null) {
                switch (cert.GWMA) {
                    case 'OA':
                    case 'PC':
                        // Don't provide reports for Feedlots
                        if (cert.Cert_Details.cert_type !== null) {
                            if (cert.Cert_Details.cert_type === 'Irrigation') {
                                return createOAReport(cert);
                            }
                        }
                        break;
                    case 'FA':
                        // Don't provide reports for Feedlots
                        if (cert.Cert_Details.cert_type === 'Irrigation') {
                            return createFAReport(cert);
                        }
                        break;
                }
            }
        }));
    }
}
const PdfPrinter = require('pdfmake/src/printer');
const fs = require('fs');

const createOAReport = data => {
    return new Promise((resolve, reject) => {
        console.log('PC or OA Cert ', data.Cert_ID);
        // console.log(data);

        let all_meters_maint = [];

        const flowmeter = data.Flowmeters[0];

        if (flowmeter.Active === true) {
            let fm_maint = [];
            fm_maint.push({
                text: `Meter Serial Number: ${flowmeter.Meter_Details.Serial_num}`
            });
            fm_maint.push({
                text: `Type of Meter: ${flowmeter.Meter_Details.Manufacturer}`
            });
            fm_maint.push({
                text: `Units: ${flowmeter.Meter_Details.units}`
            });
            fm_maint.push({
                text: `Factor: ${flowmeter.Meter_Details.factor}`
            });
            all_meters_maint.push(fm_maint);
        }

        docDefinition.content.push({
            style: 'tableExample',
            table: {
                widths: [200, 200, '*', '*'],
                body: all_meters_maint
            },
            layout: 'noBorders'
        });

        const fonts = {
                Roboto: {
                    normal: path.join(__dirname, '../', '/fonts/Roboto-Regular.ttf'),
                    bold: path.join(__dirname, '../', '/fonts/Roboto-Medium.ttf'),
                    italics: path.join(__dirname, '../', '/fonts/Roboto-Italic.ttf'),
                    bolditalics: path.join(__dirname, '../', '/fonts/Roboto-MediumItalic.ttf')
                }
        };

        const printer = new PdfPrinter(fonts);
        const pdfDoc = printer.createPdfKitDocument(docDefinition);

        // Build file path
        const fullfilePath = path.join(
            __dirname,
            '../',
            '/public/pdffiles/',
            `${data.Cert_ID}.pdf`
        );

        pdfDoc.pipe(fs.createWriteStream(fullfilePath));
        pdfDoc.on('finish', resolve); // This is where we tell it to resolve the promise when it's finished
        pdfDoc.end();
    });
};