告诉我们您的环境:
哪些步骤将重现该问题?
const puppeteer = require('puppeteer');
const run = async () => {
const browser = await puppeteer.launch();
// close any open pages
let pages = await browser.pages();
await Promise.all(pages.map(async page => await page.close()));
// handle a page being closed
browser.on('targetdestroyed', async target => {
const openPages = await browser.pages();
console.log('Open pages:', openPages.length);
if (openPages.length == 0) {
console.log('Closing empty browser');
await browser.close();
console.log('Browser closed');
}
});
pages = await browser.pages();
for (let i = 0; i < 5; i++) {
await browser.newPage();
}
pages = await browser.pages();
pages.forEach((page) => page.close());
};
run();
预期的结果是什么?
Count: 0
Open pages: 4
Open pages: 3
Open pages: 2
Open pages: 1
Open pages: 0
Closing empty browser
Browser closed
会发生什么呢?
Open pages: 4
Open pages: 3
Open pages: 2
Open pages: 1
Open pages: 0
Closing empty browser
(node:29074) UnhandledPromiseRejectionWarning: Error: Protocol error (Target.closeTarget): Target closed.
at Promise (node_modules/puppeteer/lib/Connection.js:86:56)
at new Promise (<anonymous>)
at Connection.send (node_modules/puppeteer/lib/Connection.js:85:12)
at Page.close (node_modules/puppeteer/lib/Page.js:802:36)
at pages.forEach (test.js:27:32)
at Array.forEach (<anonymous>)
at run (test.js:27:9)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
(node:29074) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:29074) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Browser closed
这不会在每次运行时都发生,但会时常发生。 我完全有可能在这里做某事_bad_!
+1
进行了一些快速调试,在确认page.close()
消息之前(或者说,木偶已处理了确认),将触发targetDestroyed
事件。
我可以想办法解决它-例如,在处理targetDestroyed
事件之前,先等待Target.closeTarget
确认。 如何正确做到这一点是另一个问题!
感谢@MJPA的调查。
问题来自以下事实: browser
在关闭关联页面之前从列表中删除了目标。
在下面的示例中,我希望browser.pages()
报告1页,直到page.close()
调用完成:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const [page] = await browser.pages();
browser.on('targetdestroyed', async () => console.log('Target destroyed. Pages count: ' + (await browser.pages()).length));
console.log('closing page...');
await page.close();
console.log('page closed.');
await browser.close();
})();
输出:
closing page...
Target destroyed. Pages count: 0
page closed.
@JoelEinbinder你怎么看?
与@MJPA相同的问题
await page.waitForSelector('aside.aside a[href="/checkout"]')
.then(() => {
logMessage('Checkout is available');
})
.catch(err => {
log('Checkout not available');
success = false;
browser.close();
});
// click checkout button
await Promise.all([
page.click('aside.aside a[href="/checkout"]'),
page.waitForNavigation()
]);
在这种情况下,总是发生相同的错误。
也许是这个操纵up的错误。
我在实现上稍有相似,但通过听page
上的close
事件,得到了相同的错误。 该文档并未对“关闭”的含义过分明确,但是根据其实现,已关闭close
_before_页面已关闭,因此以下示例不起作用,类似于targetdestroyed
示例。
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch();
// create 5 test pages
for(let i=0; i<5; i++){
let page = await browser.newPage();
// listen to page close event and close browser
// when all get closed
page.on('close', async () => {
let pages = await browser.pages();
if(!pages.length){
// will not get here!
browser.close();
}
});
}
let pages = await browser.pages();
pages.forEach(async (page) => await page.close());
我认为这种_sort of_是有意义的,因为该事件称为close
而不是closed
。 我通过在close()
promise回调中发出自己的closed
事件并听取了它的信息来解决这个问题,_does_起作用。
page.close().then(() => {
page.emit('closed');
});
这个故事的寓意似乎是没有100%保证的方法来知道何时安全关闭浏览器(而不必捕获异常)。 如果我缺少什么,请告诉我。
可能与#3423有关?
关闭浏览器中的所有标签,然后尝试打开新页面后,出现此错误
在以下示例中,我希望
browser.pages()
报告1页,直到page.close()
调用完成:
这将破坏上面示例中的代码。 最后关闭的页面brower.pages()。length为1,浏览器不会关闭。 这样就不会再有目标破坏事件发生,浏览器将永远存在。
我会说这是用户错误,尽管它很微妙。 在调用browser.close()
之前,应等待对page.close
任何调用。
如果没有用户控制的页面,只需Promise。所有页面都将关闭,然后关闭浏览器。 应该没有必要听targetdestroyed
事件。 或者只是调用browser.close并让所有页面自行关闭。
如果有用户控制的页面,则听targetdestroyed
事件,但不必调用page.close
。
+1。
使用page.on("popup")
关闭弹出窗口后,我开始看到此错误。 当弹出式窗口在Frame上下文中触发时,有时我无法使用“ popup.close()”将其关闭,并且操纵up的人使选项卡保持打开状态,因此当我尝试关闭整个浏览器时,它会引发“ Target Closed”错误,然后脚本停止。
我使用带有Chrome 73的puppeteer 1.14(我不使用Chromium)
我用来关闭浏览器的代码
async close_browser() {
for (let page of await this.browser.pages()) {
await page.close({
"runBeforeUnload": true
});
}
await this.browser.close();
}