问题描述
要将 PDF 文件从 Node.js 服务器发送到客户端,我使用以下代码:
const pdf = printer.createPdfKitDocument(docDeFinition);
const chunks = [];
pdf.on("data",(chunk) => {
chunks.push(chunk);
});
pdf.on("end",() => {
const pdfBuffered = `data:application/pdf;base64,${Buffer.concat(chunks).toString("base64")}`;
res.setHeader("Content-Type","application/pdf");
res.setHeader("Content-Length",pdfBuffered.length);
res.send(pdfBuffered);
});
pdf.end();
一切正常,唯一的问题是这里的流使用的是回调方法,而不是 async
/await
。
我发现了一个 possible solution:
const { pipeline } = require("stream/promises");
async function run() {
await pipeline(
fs.createReadStream('archive.tar'),zlib.createGzip(),fs.createWriteStream('archive.tar.gz')
);
console.log('Pipeline succeeded.');
}
run().catch(console.error);
但我不知道如何将初始代码应用于带有 stream/promises
的代码。
解决方法
如果回调只执行一次,则只能将回调 API 转换为 async
/await
。
您在网上找到的那个有效,因为您只是在回调运行一次之前等待整个流完成。您得到的是对每个传入数据块执行多次的回调。
您可以查看其他资源来使流更易于使用,例如 RXJS 或 this 即将推出的 ECMAScript 提案,以将可观察对象添加到语言中。这两者都旨在处理回调可以多次执行的情况——这是 async
/await
无法做到的。
您可以像这样手动将 PDF 代码包装在一个 promise 中,然后将其用作返回 promise 的函数:
function sendPDF(docDefinition) {
return new Promise((resolve,reject) => {
const pdf = printer.createPdfKitDocument(docDefinition);
const chunks = [];
pdf.on("data",(chunk) => {
chunks.push(chunk);
});
pdf.on("end",() => {
const pdfBuffered =
`data:application/pdf;base64,${Buffer.concat(chunks).toString("base64")}`;
resolve(pdfBuffered);
});
pdf.on("error",reject);
pdf.end();
});
}
sendPDF(docDefinition).then(pdfBuffer => {
res.setHeader("Content-Type","application/pdf");
res.setHeader("Content-Length",pdfBuffer.length);
res.send(pdfBuffer);
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
因为有很多 data
事件,所以不能只承诺数据部分。您仍然需要监听每个 data
事件并收集数据。