javascript 有没有办法在Puppeteer中使用类求值?

2guxujil  于 2023-02-18  发布在  Java
关注(0)|答案(1)|浏览(125)

考虑这个非常简单的例子:

class MyClass {
  public add(num: number): number {
    return num + 2;
  }
}
const result = await page.evaluate((NewInstance) => {
  console.log("typeof instance", typeof NewInstance); // undefined
  const d = new NewInstance();
  console.log("result", d.add(10));
  return d.add(10);
}, MyClass);

我已经尝试了我能想到的所有方法。我想在这里使用类的主要原因是,我不想直接将大量代码包含在evaluate方法中。这很混乱,很难跟踪它,所以我想将所有逻辑移动到类中,这样更容易理解正在发生的事情。
这可能吗?

eimct9ow

eimct9ow1#

这是可能的,但不一定是伟大的设计,这取决于你想做什么。在不知道实际用例的情况下,很难提出最佳解决方案,所以我只提供选项,让你做决定。
一种方法是将类字符串化(手工或使用.toString())或将其放在单独的文件中,然后使用addScriptTag

const puppeteer = require("puppeteer"); // ^19.6.3

class MyClass {
  add(num) {
    return num + 2;
  }
}

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.goto(
    "https://www.example.com",
    {waitUntil: "domcontentloaded"}
  );
  await page.addScriptTag({content: MyClass.toString()});
  const result = await page.evaluate(() => new MyClass().add(10));
  console.log(result); // => 12
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

有关更多示例,请参见this answer
eval这样的东西也是可行的,如果看起来很可怕,那么就安全性而言,你在page.evaluate()page.addScriptTag()中放入的任何东西实际上都是一样的。

const result = await page.evaluate(MyClassStringified => {
  const MyClass = eval(`(${MyClassStringified})`);
  return new MyClass().add(10);
}, MyClass.toString());

许多其他模式也是可能的,例如如果逻辑是基于节点而不是基于浏览器的,则通过exposeFunction公开库。
也就是说,在evaluate中定义类可能没有您想象的那么糟糕:

const addTonsOfCode = () => {

MyClass = class {
  add(num) {
    return num + 2;
  }
}

// ... tons of code ...
};

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.goto(
    "https://www.example.com",
    {waitUntil: "domcontentloaded"}
  );
  await page.evaluate(addTonsOfCode);
  const result = await page.evaluate(() => new MyClass().add(10));
  console.log(result); // => 12
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

我更愿意将这些命名为一个库:

const addTonsOfCode = () => {

class MyClass {
  add(num) {
    return num + 2;
  }
}

// ... tons of code ...

window.MyLib = {
  MyClass,
  // ...
};

};

然后配合使用:

await page.evaluate(addTonsOfCode);
await page.evaluate(() => new MyLib.MyClass().add(10));

相关问题