木偶|等待所有JavaScript执行 [英] Puppeteer | Wait for all JavaScript is executed

查看:65
本文介绍了木偶|等待所有JavaScript执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试从多个页面中截取屏幕截图,这些页面应完全加载(包括延迟加载的图像),以便以后进行比较.

I try to take screenshots from multiple pages, which should be fully loaded (including lazy loaded images) for later comparison.

我找到了 lazyimages_without_scroll_events.js示例,它很有帮助.

I found the lazyimages_without_scroll_events.js example which helps a lot.

使用以下代码,屏幕快照看起来不错,但是存在一些主要问题.

With the following code the screenshots are looking fine, but there is some major issue.

async function takeScreenshot(browser, viewport, route) {
  return browser.newPage().then(async (page) => {
    const fileName = `${viewport.directory}/${getFilename(route)}`;

    await page.setViewport({
      width: viewport.width,
      height: 500,
    });
    await page.goto(
        `${config.server.master}${route}.html`,
        {
          waitUntil: 'networkidle0',
        }
    );
    await page.evaluate(() => {
      /* global document,requestAnimationFrame */
      let lastScrollTop = document.scrollingElement.scrollTop;

      // Scroll to bottom of page until we can't scroll anymore.
      const scroll = () => {
        document.scrollingElement.scrollTop += 100;
        if (document.scrollingElement.scrollTop !== lastScrollTop) {
          lastScrollTop = document.scrollingElement.scrollTop;
          requestAnimationFrame(scroll);
        }
      };
      scroll();
    });
    await page.waitFor(5000);
    await page.screenshot({
      path: `screenshots/master/${fileName}.png`,
      fullPage: true,
    });

    await page.close();
    console.log(`Viewport "${viewport.name}", Route "${route}"`);
  });
}

问题:即使page.waitFor()的值(超时)较高,有时也无法完全执行页面上所有与前端相关的JavaScript.

Issue: Even with higher values for page.waitFor() (timeout), sometimes not the all of the frontend related JavaScripts on the pages were fully executed.

对于某些较旧的页面,其中某些JavaScript可能会更改前端. F.e.在一种传统情况下,为jQuery.matchHeight.

For some older pages where some JavaScript could change the frontend. F.e. in one legacy case a jQuery.matchHeight.

最佳情况:在理想情况下,Puppeteer会等到所有JavaScript都被评估并执行后再进行. 这可能吗?

Best case: In an ideal world Puppeteer would wait till all JavaScript is evaluated and executed. Is something like this possible?

编辑
cody-g的帮助下,我可以对脚本进行一些改进.

EDIT
I could improve the script slightly with the help from cody-g.

function jQueryMatchHeightIsProcessed() {
  return Array.from($('.match-height')).every((element) => {
    return element.style.height !== '';
  });
}

// Within takeScreenshot() after page.waitFor()
await page.waitForFunction(jQueryMatchHeightIsProcessed, {timeout: 0});

...但这远非完美.看来我必须为不同的前端脚本找到类似的解决方案,才能真正考虑目标页面上发生的所有事情.

... but it is far from perfect. It seems I have to find similar solutions for different frontend scripts to really consider everything which happening on the target page.

在我的情况下,jQuery.matchHeight的主要问题是它在不同的行程中处理不同的高度.可能是由于图像延迟加载引起的.看来我必须等到可以用Flexbox替换它. (^ _ ^)°

The main problem with jQuery.matchHeight in my case is that it does process different heights in different runs. Maybe caused by image lazyloading. It seems I have to wait until I can replace it with Flexbox. (^_^)°

其他要解决的问题:

禁用动画:

await page.addStyleTag({
  content: `
    * {
      transition: none !important;
      animation: none !important;
    }
  `,
});

处理幻灯片:

function handleSwiperSlideshows() {
  Array.from($('.swiper-container')).forEach((element) => {
    if (typeof element.swiper !== 'undefined') {
      if (element.swiper.autoplaying) {
        element.swiper.stopAutoplay();
        element.swiper.slideTo(0);
      }
    }
  });
}

// Within takeScreenshot() after page.waitFor()
await page.evaluate(handleSwiperSlideshows);

但仍然不够.我认为不可能对这些旧页面进行视觉测试.

But still not enough. I think it's impossible to visual test these legacy pages.

推荐答案

以下

The following waitForFunction might be useful for you, you can use it to wait for any arbitrary function to evaluate to true. If you have access to the page's code you can set the window status and use that to notify puppeteer it is safe to continue, or just rely on some sort of other ready state. Note: this function is a polling function, and re-evaluates at some interval which can be specified.

const watchDog = page.waitForFunction('<your function to evaluate to true>');

例如,

const watchDog = page.waitForFunction('window.status === "ready"');
await watchDog;

只需在页面代码中将window.status设置为ready

In your page's code you simply need to set the window.status to ready

要在多个异步文件中利用多个看门狗,您可以执行类似的操作

To utilize multiple watchdogs in multiple asynchronous files you could do something like

index.js

...import/require file1.js;
...import/require file2.js;
...code...

file1.js:

var file1Flag=false; // global
...code...
file1Flag=true;

file2.js:

var file2Flag=false; // global
...code...
file2Flag=true;

main.js:

const watchDog = page.waitForFunction('file1Flag && file2Flag');
await watchDog;

这篇关于木偶|等待所有JavaScript执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆