在没有回调的情况下使用 Node.js 流
Working with Node.js streams without callbacks
要从 Node.js 服务器向客户端发送 PDF 文件,我使用以下代码:
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
。
我找到了 :
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, or this 即将推出的 ECMAScript 提议,将可观察对象添加到该语言中。这两个都是为了处理回调可以执行多次的场景——这是 async
/await
做不到的。
您可以手动将 PDF 代码包装在这样的承诺中,然后将其用作 returns 承诺的函数:
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
事件并收集数据。
要从 Node.js 服务器向客户端发送 PDF 文件,我使用以下代码:
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
。
我找到了
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, or this 即将推出的 ECMAScript 提议,将可观察对象添加到该语言中。这两个都是为了处理回调可以执行多次的场景——这是 async
/await
做不到的。
您可以手动将 PDF 代码包装在这样的承诺中,然后将其用作 returns 承诺的函数:
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
事件并收集数据。