NodeJS使用Puppeteer时Async主函数执行完成后程序不退出
根本原因
Node.js 进程自动退出的前提是事件循环中没有待处理的异步任务,也没有活跃的 I/O 句柄/定时器。
你代码中调用 puppeteer.launch() 启动 Chromium 实例后,Puppeteer 会和 Chromium 进程保持 WebSocket 长连接用于通信,这个连接属于持续活跃的 I/O 句柄,会一直挂载在事件循环中,因此哪怕你的业务逻辑代码全部执行完毕,进程也不会自动退出。
你删除 await ts.init() 后进程能正常退出,就是因为没有启动浏览器、没有创建这个活跃的长连接句柄。
标准解决方案
不要用 process.exit() 强制杀进程,这种方式可能导致 Chromium 进程没有被正常销毁,后台残留僵尸进程占用系统资源。正确做法是业务逻辑执行完毕后主动关闭浏览器实例:
- 先修改
TS类,把 browser 实例挂载到类属性上,方便后续调用关闭方法 - 所有操作完成后主动调用
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
相关产品推荐
相关产品推荐

