如何基于PDFMake实现异步PDF生成?createPdfKitDocument能否非阻塞?
问题解答
首先明确:printer.createPdfKitDocument本身是同步执行的CPU密集型操作(PDF排版、渲染逻辑均为同步计算),无法直接改成异步API,但可以通过将PDF生成任务隔离到独立线程/进程的方式,避免阻塞主API的事件循环,从而解决并发请求下响应延迟的问题。
具体实现方案
1. 使用Node.js worker_threads 模块(推荐)
把PDF生成的核心逻辑放到Worker线程中,主进程仅负责接收请求、分发任务和接收结果,这样主事件循环不会被CPU密集的PDF生成操作阻塞,多个并发请求可以并行处理。
主进程代码:
const { Worker } = require('worker_threads'); function generatePdf(data) { return new Promise((resolve, reject) => { const worker = new Worker('./pdf-generator-worker.js', { workerData: data }); worker.on('message', (result) => { if (result.error) reject(new Error(result.error)); else resolve(result); }); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) reject(new Error(`PDF生成线程异常退出,代码:${code}`)); }); }); }
Worker线程文件(pdf-generator-worker.js):
const { parentPort, workerData } = require('worker_threads'); const PdfPrinter = require('pdfmake'); const fs = require('fs'); const randomstring = require('randomstring'); const FONTS = require('./your-font-config-path'); // 替换为你的字体配置路径 const ReporteCompVenta = require('./your-reporte-class-path'); // 替换为你的报表类路径 try { const printer = new PdfPrinter(FONTS); const reporte = new ReporteCompVenta(workerData, 'A4'); const pdfDoc = printer.createPdfKitDocument(reporte.generar(), {}); const fileName = `files/${randomstring.generate(5)}.pdf`; pdfDoc.pipe(fs.createWriteStream(fileName) .on('error', (err) => { parentPort.postMessage({ error: err.message }); }) ); pdfDoc.on('end', () => { parentPort.postMessage({ success: true, fileName }); }); pdfDoc.end(); } catch (err) { parentPort.postMessage({ error: err.message }); }
2. 使用进程池(适合高并发场景)
如果Worker线程的隔离力度不够,或者需要更严格的资源控制,可以用进程池(比如借助poolifier库,或自行实现子进程池),限制同时运行的PDF生成进程数量,避免服务器资源耗尽。
现有代码的优化点
- 移除测试用的
setTimeout,避免无意义的延迟 - Promise构造函数中的
catch块里,应该用reject(err)替代throw(err),否则会导致未捕获的Promise拒绝错误
内容的提问来源于stack exchange,提问作者dssof
相关产品推荐
相关产品推荐

