You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

我该使用worker还是child process运行可按pid终止的puppeteer函数?

方案选型结论
  • 优先选用**Child Process(子进程)**实现,不要使用Worker Thread,原因如下:
    • Worker Thread属于同一主进程下的多线程,所有线程共享同一个进程PID,无法实现按独立PID终止指定任务的需求
    • 子进程拥有独立的PID、内存空间,Puppeteer实例崩溃不会影响主进程运行,完全符合独立隔离、单独终止的要求
  • process.kill(child.pid)完全可以实现终止指定子进程的操作,只要提前存储每个子进程的PID和实例映射关系即可。

前置依赖安装

先安装所需依赖:
npm install puppeteer

1. job.js 代码(子进程执行文件)

const puppeteer = require('puppeteer');

let browser = null;

// 子进程启动后自动运行Puppeteer实例
(async () => {
  try {
    browser = await puppeteer.launch({
      headless: 'new',
      // 此处可添加你需要的其他puppeteer配置
    });
    // 通知主进程启动成功,携带当前子进程PID
    process.send({
      type: 'start_success',
      pid: process.pid,
      browserWSEndpoint: browser.wsEndpoint()
    });

    // 此处添加你需要的Puppeteer业务逻辑
    // 示例:打开百度
    const page = await browser.newPage();
    await page.goto('https://www.baidu.com');
    console.log('页面加载完成,子进程PID:', process.pid);

  } catch (err) {
    process.send({
      type: 'error',
      pid: process.pid,
      msg: err.message
    });
    process.exit(1);
  }
})();

// 监听主进程的终止信号,先关闭浏览器再退出,避免残留Chrome进程
process.on('message', async (msg) => {
  if (msg.type === 'stop') {
    if (browser) await browser.close();
    process.exit(0);
  }
});

// 子进程退出前强制关闭浏览器,防止资源残留
process.on('exit', async () => {
  if (browser) await browser.close();
});

2. main.js 代码(主进程,带启动/停止逻辑)

const { fork } = require('child_process');
const path = require('path');

// 存储子进程映射:key为pid,value为子进程实例
const childProcessMap = new Map();

// 启动按钮点击触发的函数
function startJob() {
  // fork创建子进程执行job.js
  const child = fork(path.join(__dirname, 'job.js'));
  
  // 存储子进程实例
  childProcessMap.set(child.pid, child);
  console.log('启动子进程,PID:', child.pid);

  // 监听子进程消息
  child.on('message', (data) => {
    if (data.type === 'start_success') {
      console.log(`子进程${data.pid}的Puppeteer启动成功`);
    } else if (data.type === 'error') {
      console.log(`子进程${data.pid}报错:`, data.msg);
      childProcessMap.delete(data.pid);
    }
  });

  // 监听子进程退出,清除映射避免内存泄漏
  child.on('exit', (code) => {
    console.log(`子进程${child.pid}退出,退出码:`, code);
    childProcessMap.delete(child.pid);
  });

  return child.pid;
}

// 停止按钮点击触发的函数,传入要停止的子进程pid
function stopJob(pid) {
  const child = childProcessMap.get(pid);
  if (!child) {
    console.log(`不存在PID为${pid}的子进程`);
    return false;
  }

  // 先发送优雅停止信号,让子进程主动关闭浏览器再退出
  child.send({ type: 'stop' });

  // 3秒后如果子进程仍未退出,强制杀进程
  setTimeout(() => {
    if (childProcessMap.has(pid)) {
      try {
        process.kill(pid, 'SIGKILL');
        childProcessMap.delete(pid);
        console.log(`强制杀死子进程${pid}成功`);
      } catch (err) {
        console.log(`杀死子进程${pid}失败:`, err.message);
        childProcessMap.delete(pid);
      }
    }
  }, 3000);

  return true;
}

// 测试代码:启动后10秒自动停止
// const testPid = startJob();
// setTimeout(() => {
//   stopJob(testPid);
// }, 10000);

// 如果你是GUI场景,将startJob和stopJob绑定到对应按钮的点击事件即可

注意事项

  • 杀死子进程前优先触发Puppeteer的browser关闭逻辑,避免残留孤立的Chrome进程占用系统资源,上述代码已经做了相关处理
  • 每次点击启动按钮调用一次startJob()即可创建独立的Puppeteer实例,每个实例都有独立PID,互不影响
  • Windows系统下极少数场景process.kill可能无法杀全进程树,可额外引入tree-kill包处理

内容的提问来源于stack exchange,提问作者noobcode0000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 00:24:02