Puppeteer多窗口操作出现Target closed错误的原因及解决
Puppeteer 19.0.0 多窗口操作后出现「Target closed」错误的排查与解决
错误原因分析
- 异步回调残留触发:多窗口操作时,新页面的CDP(Chrome DevTools Protocol)会话可能残留未完成的异步回调,调用
browser.close()断开连接时,这些回调会因目标已关闭抛出错误。这类错误在事件循环微任务中触发,常规try/catch无法捕获。 - 页面关闭逻辑冲突:手动遍历关闭所有页面后,
browser.close()会再次尝试处理已关闭的页面,导致Puppeteer内部状态不一致,触发错误。 - 新页面引用管理不当:打开新窗口时未正确追踪页面实例,或操作后未妥善关闭,导致Puppeteer持有无效页面引用,清理阶段触发错误。
解决办法
1. 优化销毁方法,避免重复操作
Puppeteer调用browser.close()时会自动关闭所有页面,无需手动遍历。若必须手动关闭页面,需为每个操作添加错误捕获:
public async destroy() { let browserIsConnected: boolean = !!this._browser?.isConnected(); if (this._browser && browserIsConnected) { try { const pages = await this._browser.pages(); for (let pg of pages) { try { this.logger.debug(`Closing page ${pg.url()}`); // 强制关闭,忽略已关闭页面的错误 await pg.close({ force: true }); } catch (e) { this.logger.debug(`Skip closed page: ${pg.url()}`); } } this.logger.debug(`Closing browser instance...`); // 移除所有事件监听,避免残留回调触发错误 this._browser.removeAllListeners(); await this._browser.close(); this.logger.log(`Closed browser connection`); } catch (e) { this.logger.error(`Cleanup error: ${e}`); } finally { delete this._browser; } } else { this.logger.log(`Browser already destroyed`); delete this._browser; } }
2. 规范多窗口操作的页面生命周期
打开新窗口时,必须通过waitForTarget正确获取页面实例,操作完成后及时关闭:
// 监听新页面创建 const newPagePromise = this._browser.waitForTarget( target => target.type() === 'page' && !target.url().startsWith('about:blank') ); // 触发打开新窗口的操作(如点击链接) await mainPage.click('a[target="_blank"]'); // 获取新页面实例 const newPage = await newPagePromise; // 执行新页面操作 await newPage.waitForSelector('#target-element'); // ...其他业务逻辑 // 操作完成后关闭新页面 await newPage.close();
3. 升级Puppeteer版本
Puppeteer 19.0.0存在多窗口处理的已知bug,升级到20.x及以上版本可修复多数此类问题。
4. 过滤全局异步未捕获错误
针对异步抛出的「Target closed」错误,可在代码入口添加全局监听避免测试失败:
process.on('unhandledRejection', (reason) => { // 过滤目标关闭错误,不影响测试结果 if (reason?.toString().includes('Target closed')) return; console.error('Unhandled Rejection:', reason); });
内容的提问来源于stack exchange,提问作者Agus Neira
相关产品推荐
相关产品推荐

