Nodejs使用队列(以截图网址对应页面为例)
初始化项目(空文件夹下)
js
npm init -y
安装相关包
js
// 截图相关
npm i puppeteer
npm i puppeteer-core // 用不上,但是必须要下,被puppeteer所依赖
// 服务器相关
npm install express
根目录下创建队列处理文件
worker.js
js
const puppeteer = require('puppeteer');
const { parentPort } = require('worker_threads');
async function capturePage(url) {
// 下面的try里面写具体的业务逻辑(异步执行的逻辑代码,例如下面的截图逻辑)
try {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
// 设置视口,deviceScaleFactor 影响清晰度
// 下面这个可以根据ui尺寸设计
// 打开的窗口大小(短图海报,不含按钮)
await page.setViewport({ width: 750, height: 1320, deviceScaleFactor: 2 });
// 导航到目标网页
await page.goto(url);
// 等待页面加载完成
await new Promise(resolve => setTimeout(resolve, 2000)); // 等待 2 秒
// 获取页面内容高度并调整视口
const bodyHandle = await page.$('body');
const boundingBox = await bodyHandle.boundingBox();
await bodyHandle.dispose();
// 这个设置截图的图片的宽高大小
await page.setViewport({
width: 750,
height: Math.ceil(boundingBox.height),
deviceScaleFactor: 2
});
let fileName = Date.now() + '.png';
// 截取长页面截图
await page.screenshot({ path: fileName });
// 关闭浏览器
await browser.close();
return fileName;
} catch (error) {
return error;
}
}
// 监听主文件app.js发送的消息
parentPort.on('message', async ({ url }) => {
const result = await capturePage(url);
parentPort.postMessage(result);
});
根目录下app.js
代码
js
const express = require('express');
const { Worker } = require('worker_threads');
const app = express();
const maxThreads = 5; // 默认最大线程数
let threadPool = []; // 线程池
let queue = []; // 等待任务的队列
app.use(express.json());
// 初始化线程池(初始化时创建5个线程)
for (let i = 0; i < maxThreads; i++) {
threadPool.push(createWorker());
}
// 创建新线程并运行
function createWorker() {
return {
busy: false,
worker: new Worker('./worker.js'),
};
}
// 动态分配线程
function assignTaskToWorker(url) {
const availableWorker = threadPool.find((w) => !w.busy);
// 如果有可用线程,分配任务(busy为false代表线程空闲,线程可用)
if (availableWorker) {
availableWorker.busy = true; // 标记为忙碌
availableWorker.worker.postMessage({ url }); // 发送消息给worker
availableWorker.worker.once('message', (msg) => { // 接收worker的消息
console.log(`任务完成:${msg}`); // 处理结果
availableWorker.busy = false; // 标记为空闲
if (queue.length > 0) {
const nextTask = queue.shift();
assignTaskToWorker(nextTask);
}
});
} else {
// 如果没有可用线程,将任务加入队列
queue.push(url);
console.log('所有线程都在忙,任务已加入队列');
}
}
// 接受 POST 请求
app.post('/capture', (req, res) => {
const { url } = req.body; // 获取到参数信息
if (!url) {
// 缺少参数
return res.status(400).send('请输入有效的 URL');
}
console.log(`接受到新任务: ${url}`);
// 进入队列执行
assignTaskToWorker(url);
res.send('任务已提交');
});
// 启动服务器
app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
运行项目
js
node .\app.js
打开apifox
,新建接口,地址为:http://127.0.0.1:3000/capture
,参数选择body
-json
,内容如下:
js
{
"url":"https://www.baidu.com/"
}
多次频繁请求接口,查看控制台打印信息以及侧边文件新增的图片信息即可