无法导出从人偶浏览器创建的 wsEndpoint

Can't export wsEndpoint created from puppeteer browser

我试图在启动时打开一个 puppeteer 浏览器,然后导出 wsEndpoint,这样我就可以使用 link 连接到浏览器,而不是每次调用该函数时都打开一个新浏览器。

这是文件 app.js 中的代码片段,它是节点的入口点。

const mainFunction = async () => {
    const browser = await puppeteer.launch()
    const wsEndpoint = browser.wsEndpoint()
    return wsEndpoint
}

mainFunction().then(async endpoint => {
    console.log(endpoint)
    module.exports = endpoint
})

启动后,控制台日志 returns a link 然后我导出 这是实用程序文件中的代码片段 equities.js

const puppeteer = require("puppeteer")
const endpoint = require("../../app.js")
module.exports = async(symbol)=>{
  console.log(endpoint)
  const browser = await puppeteer.connect({connectWSEndpoint: endpoint})

}

每次调用该函数时,控制台仅记录 returns 一个空对象,这意味着 app.js 中的导出由于某种原因失败。我尝试 google 一些东西并尝试了不同的导出方式,但 none 似乎有效。有人可以帮助指导我吗?非常感谢您。

我觉得这里有些地方不对劲——这段代码感觉好像没有经过测试,导致了多点故障。尝试采取更小的步骤,这样您就可以隔离问题而不是累积问题。


首先,mainFunction 代码放弃了 browser 对象,创建了无法关闭的泄漏子进程资源。

我会 return 或将 browser 变量与端点一起存储,以便有人可以通过函数清理它。或者只是 return browser 并让客户端代码根据需要将端点从中拉出,以及管理和关闭资源。


接下来导出代码:

mainFunction().then(async endpoint => {
    console.log(endpoint)
    module.exports = endpoint
})

我不明白这个额外的 then 包装器接收一个从未使用 awaitasync 解析函数的动机。您可能认为节点 await 包含所有这些代码,然后在客户端文件的 require 同步运行之前设置 module.exports 值。那就是not the case,可以用一段更简单的代码来确定:

app.js(为方便起见,在整个 post 的同一文件夹中):

const mainFunction = async () => 42;

mainFunction().then(async endpoint => {
    console.log("endpoint":, endpoint)
    module.exports = endpoint
})

index.js:

const endpoint = require("./app");

console.log("imported:", endpoint);

node index 给我:

imported: {}
endpoint: 42

承诺在 require 之后解决,它同步引入了默认的空白对象 module.exports -- 可能不是您所期望的。

如果你有异步代码,它必须永远保持异步,包括导出和导入。尝试直接导出承诺,然后 await 在客户端中执行它:

app.js:

const mainFunction = async () => 42;
module.exports = mainFunction;

index.js:

const getEndpoint = require("./app");

getEndpoint().then(endpoint => console.log("imported:", endpoint));

运行ning node index 给我:imported: 42.


equities.js 中的客户端代码看起来更合理,因为它同步导出一个 promise,但它必须 await endpoint promise 它在任何使用它的地方导入。

此外,Puppeteer 在 puppeteer.connect({connectWSEndpoint: endpoint})Error: Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect 上抛出。我会把它留给你根据你的目标来解决。

这是修复承诺问题的重写草图,但这只是一个概念证明,需要进行调整才能完成您想要做的任何事情:

app.js:

const puppeteer = require("puppeteer");

const browserPromise = puppeteer.launch();

const endpointPromise = browserPromise
  .then(browser => browser.wsEndpoint())
;

module.exports = {browserPromise, endpointPromise};

equities.js:

const puppeteer = require("puppeteer");
const {browserPromise, endpointPromise} = require("./app");

module.exports = async symbol => {
  const endpoint = await endpointPromise;
  console.log(endpoint);
  //const browser = await puppeteer.connect({connectWSEndpoint: endpoint}) // FIXME
  const browser = await browserPromise;
  await browser.close();
};

index.js:

const equitiesFn = require("./equities");

(async () => {
  await equitiesFn();
})();

运行 node index 你应该会看到打印的 ws。

请注意,如果需要,您可以将导出的承诺包装在函数中或作为对象的一部分,对象是库接口更典型的抽象层。但这并没有改变基本的异步性。客户端将调用导出的函数并等待端点 and/or 浏览器承诺通过额外的间接层,

require("./app").getBrowser().then(browser => /* */);

对比

require("./app").browserPromise.then(browser => /* */);

如果您不想公开浏览器对象,那很好,但我建议公开一个关闭底层浏览器的函数,这样您就可以干净地退出,例如

app.js:

const puppeteer = require("puppeteer");

const browserPromise = puppeteer.launch();

const closeBrowser = () => 
  browserPromise.then(browser => browser.close())
;

module.exports = {closeBrowser};

index.js:

require("./app")
  .closeBrowser()
  .then(() => console.log("closed"))
;