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

NodeJS使用Puppeteer时Async主函数执行完成后程序不退出

根本原因

Node.js 进程自动退出的前提是事件循环中没有待处理的异步任务,也没有活跃的 I/O 句柄/定时器。
你代码中调用 puppeteer.launch() 启动 Chromium 实例后,Puppeteer 会和 Chromium 进程保持 WebSocket 长连接用于通信,这个连接属于持续活跃的 I/O 句柄,会一直挂载在事件循环中,因此哪怕你的业务逻辑代码全部执行完毕,进程也不会自动退出。
你删除 await ts.init() 后进程能正常退出,就是因为没有启动浏览器、没有创建这个活跃的长连接句柄。

标准解决方案

不要用 process.exit() 强制杀进程,这种方式可能导致 Chromium 进程没有被正常销毁,后台残留僵尸进程占用系统资源。正确做法是业务逻辑执行完毕后主动关闭浏览器实例:

  1. 先修改 TS 类,把 browser 实例挂载到类属性上,方便后续调用关闭方法
  2. 所有操作完成后主动调用 browser.close() 销毁实例、断开连接

修改后的代码示例:

var UserAgent = require('user-agents');
const userAgent = new UserAgent();
const puppeteer = require('puppeteer-extra');

const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());

class TS {
    constructor() {
        this.page = null;
        this.browser = null; // 新增:存储browser实例
    }
    
    async init() {
        this.browser = await puppeteer.launch({ headless: false });
        this.page = await this.browser.newPage();
        await this.page.setUserAgent(userAgent.toString());        
    }

    // 新增:销毁实例方法
    async destroy() {
        await this.browser.close();
    }
}


async function main(params) {
    console.log("Started main..");
    const ts = new TS();
    await ts.init();

    // --- 这里放你的业务逻辑代码 ---

    // 业务逻辑执行完后关闭浏览器
    await ts.destroy();
    console.log("Ending main..");
}

main().catch(e => console.error(e));

修改后执行完所有代码,浏览器会正常关闭,长连接断开后事件循环没有活跃句柄,Node.js 进程就会自动退出。

特殊场景说明

如果你确实有需求需要保留浏览器后台运行、又要让Node.js进程退出,才建议使用 process.exit(),但要注意定期清理残留的 Chromium 进程,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 11:39:03