node.js - 使用 Express 作为 HTML 服务器的 NodeJS --> PDF 生成。能有效率吗?
问题描述
我知道 NodeJS 的事件循环和单线程特性。鉴于此,您认为继续开发 NodeJS/Express 服务,我们可以使用它来将 HTML 部分转换为 PDF 页面是一个好主意吗?
我们正在考虑 Puppeteer。我已经使用过它并且效果很好,但我不确定组织中的每个用户是否都必须等待事件循环,因为每个请求都会让进程一直忙到最后?
解决方案
事件循环
事件循环负责处理 JavaScript 的“单线程事件驱动”性质,这意味着需要执行的异步 (JavaScript) 代码将被放入队列中并一个接一个地执行(通过循环)使用更经典的多线程方法。有关此主题的更多信息,我推荐这个很棒的视频解释。
事件循环与您的问题并不真正相关,因为大部分工作在浏览器内异步发生(而不是在 Node.js 运行时内)。这意味着您的 puppeteer 脚本将大部分时间等待浏览器返回结果。
考虑这样一个简单的行:
await browser.newPage();
这实际上是做什么的?它将命令发送到浏览器(在另一个进程中运行)以打开页面。实际工作发生在浏览器内部,而不是在您的 Node.js 环境中。基本上所有的 puppeteer 功能也是如此。因此,“主要工作”不会发生在您的 Node.js 环境中,因此事件循环与您的问题无关。
实施
您所描述的对于 puppeteer 和 Node.js 是绝对可行的。让我们考虑一下这个示例代码,它应该可以帮助您入门:
const puppeteer = require('puppeteer');
const express = require('express');
const app = express();
app.get('/pdf', async (req, res) => { // Call /pdf?url=... to create a PDF of the provided URL
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(req.query.url); // URL is given by the user
const pdfBuffer = await page.pdf();
// Respond with the PDF
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Length': pdfBuffer.length
});
res.end(pdfBuffer);
await browser.close();
});
app.listen(4000);
这将提供一个 API 来生成 URL 的 PDF。每个请求都会打开一个浏览器,打开一个新页面,导航到给定的 URL 并将 PDF 返回给用户。由于 JavaScript 的异步环境,这将完全并行发生。只要您的机器可以处理并行打开的浏览器的数量,就可以了。
进一步改进
虽然给定的脚本有效,但您应该记住,由于打开的浏览器过多,过多的请求可能会很快消耗过多的内存/CPU,从而导致资源问题。为了改进实施,您希望使用 puppeteer 资源池来处理流量。为此,您可能需要查看puppeteer-cluster(免责声明:我是作者),它为您提供浏览器实例池,并允许限制正在运行的浏览器的数量。该库可以轻松处理此用例。对于这个确切的用例,实际上有一个在线示例(但是,它会生成屏幕截图而不是 PDF)。
推荐阅读
- typescript - 如何修复打字稿查找类型中的错误?
- java - 如果 SQLite 中的列为空,则显示“No Title”
- python - 如何在 Tensorflow 2 中解码示例(从 1.12 移植)
- html - CSS Grid在换行后具有自动流可能的最小列数
- wcf - 从服务器收到的身份验证标头.. BASIC - WFC - NET CORE
- google-apps-script - getValue() 不从源文件中返回数据,Google App Script
- javascript - 用 Applescript 在线替换文本
- kubernetes - Kubernetes 网络插件
- php - php排序多嵌套数组
- codeigniter - codeigniter form_error() 在表单控件旁边没有显示错误