1 回答
TA贡献1852条经验 获得超1个赞
是的,你说得很对,这可能会引起混淆。
例子
const document = /* ... */;
await page.waitFor(() => !!document.querySelector('.foo'));
看起来代码正在document从上面访问变量,但这实际上并不是这里发生的事情,即使您的 IDE/语法高亮可能会告诉您它是相同的变量。
解释
Node.js 环境和浏览器环境是两个独立的 (JavaScript) 环境,它们通过 WebSocket 进行通信。因此,当您在 Node.js 环境中的页面上执行函数时,puppeteer 需要将该函数作为字符串发送到浏览器。对于这个puppeteer 将调用toString()给定函数上的函数,该函数只返回您写下的高级代码。该字符串将被发送到浏览器并在其环境中执行。
这也是您可以将字符串而不是函数传递给 puppeteer 的原因。如果您提交的是字符串而不是函数,则代码将在浏览器环境中执行。
举个例子,考虑这两行,它们做同样的事情(打印123到控制台):
console.log(await page.evaluate(() => 123));
console.log(await page.evaluate('(() => 123)()'));
在第一行中,该函数作为函数传递(并且 puppeteer 会将其转换为字符串并为您调用该函数)。在第二行中,传递了相同的函数,但这次我们必须自己调用它(函数周围的额外括号仅出于语法原因才需要)。
为什么它会这样工作?
为方便起见,Puppeteer 允许将函数作为函数(而不仅仅是作为字符串)传递。允许这样做,可以很容易地发现任何小错误,例如缺少括号,因为它们已经被您的 Node.js 环境拾取(您的“Node.js JavaScript Parser”仍将解析您的函数)。此外,它还可以轻松地在您的代码编辑器中使用语法高亮。
但是,是的,很容易忘记这个抽象层意味着您使用的任何参数都需要作为单独的参数传递,如下所示:
const value1 = 123;
await page.evaluate((value1) => { /... */ }, value1);
总而言之,如果您发现它令人困惑,您始终可以将代码放入一个单独的文件中,读取该文件并将其内容作为字符串在调用 puppeteer 函数时传递。这允许更好地分离您的代码。值得付出努力吗?你必须自己决定...
添加回答
举报