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

Puppeteer中setTimeout延迟失效,浏览器提前关闭报错求助

Puppeteer延迟后浏览器提前关闭问题排查

问题描述

我创建了waitForTimeout函数,想在Puppeteer打开新页面后实现可await的延迟,但实际浏览器打开页面后立即关闭,只有Node端会延迟10秒,随后抛出页面已关闭的错误。按逻辑await browser.close()应该在延迟完成后执行,却出现异常。

原代码

function waitForTimeout(timeout) {
  return new Promise((resolve) => {
    setTimeout(resolve, timeout)
  })
}

const puppet = () => {
  getCookies(async (cookies) => {
    const browser = await puppeteer.launch({
      headless: false
    });

    const page = await browser.newPage();
    await page.setCookie(...cookies);
    await page.goto("https://ipchicken.com");

    await waitForTimeout(10000)

    let data = await page.evaluate(()=>{
      const ip = document.querySelector("body > table:nth-child(2) > tbody > tr > td:nth-child(3) > p:nth-child(2) > font > b").textContent
      return ip;
    })
    console.log(data)
    await browser.close();
  });
}

报错信息

/Users/macbook/repos/operation-tss/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:316
            return Promise.reject(new Error(`Protocol error (${method}): Session closed. Most likely the ${__classPrivateFieldGet(this, _CDPSessionImpl_targetType, "f")} has been closed.`));
                                  ^

Error: Protocol error (Runtime.callFunctionOn): Session closed. Most likely the page has been closed.
    at CDPSessionImpl.send (/Users/macbook/repos/operation-tss/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:316:35)
    at ExecutionContext._ExecutionContext_evaluate (/Users/macbook/repos/operation-tss/node_modules/puppeteer-core/lib/cjs/puppeteer/common/ExecutionContext.js:211:46)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async ExecutionContext.evaluate (/Users/macbook/repos/operation-tss/node_modules/puppeteer-core/lib/cjs/puppeteer/common/ExecutionContext.js:107:16)

问题原因

核心问题是回调嵌套导致的异步控制流混乱:

  • 你将async函数作为回调传给了getCookies,但getCookies是传统的回调式API,不会处理async函数返回的Promise。这意味着回调内部的异步操作(比如await puppeteer.launch、await waitForTimeout)会脱离外部控制流的管理。
  • 当getCookies调用完回调后,它的任务就已完成,puppet函数也会立即执行完毕。此时回调内的异步操作处于“游离”状态,可能因为Node.js事件循环的资源回收逻辑,或者getCookies内部的上下文销毁逻辑,导致Puppeteer的页面实例被提前关闭,最终在执行page.evaluate时报错。

解决方法

将基于回调的getCookies转换为Promise形式,使用线性的async/await控制流替代回调嵌套,确保所有异步操作都被正确等待。

修改后的代码

const util = require('util');

function waitForTimeout(timeout) {
  return new Promise((resolve) => {
    setTimeout(resolve, timeout)
  })
}

const puppet = async () => {
  // 将回调式的getCookies转换为Promise形式
  const getCookiesPromise = util.promisify(getCookies);
  const cookies = await getCookiesPromise();

  const browser = await puppeteer.launch({
    headless: false
  });

  const page = await browser.newPage();
  await page.setCookie(...cookies);
  await page.goto("https://ipchicken.com");

  // 也可以直接使用Puppeteer内置的延迟方法,替代自定义的waitForTimeout
  // await page.waitForTimeout(10000);
  await waitForTimeout(10000);

  const data = await page.evaluate(() => {
    const ip = document.querySelector("body > table:nth-child(2) > tbody > tr > td:nth-child(3) > p:nth-child(2) > font > b").textContent;
    return ip;
  });

  console.log(data);
  await browser.close();
};

额外优化

可以直接使用Puppeteer内置的page.waitForTimeout()方法,无需自定义waitForTimeout函数,更符合Puppeteer的官方使用规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 03:50:40