【问题标题】:puppeteer wait for page update after button click (no navigation)puppeteer 按钮单击后等待页面更新(无导航)
【发布时间】:2019-12-28 22:52:42
【问题描述】:

第一次尝试puppeteer,真是太棒了。 单击按钮后,我需要等待页面获取和呈现新数据。这不会导致导航(网址相同)因此以下代码不起作用(它给出超时异常):

await Promise.all([
    myButton.click()
    page.waitForNavigation()
])

等待页面在点击时获取/呈现异步数据的正确方法是什么?

【问题讨论】:

    标签: javascript puppeteer


    【解决方案1】:

    假设 DOM 以某种方式发生变化,您可以等待特定元素或选择器。

    可能会出现图像。

    await myButton.click();
    await page.waitForSelector('img.success');
    
    

    也许某些具有 ID 属性的元素被插入到 DOM 中。

    await myButton.click();
    await page.waitForSelector('#newElementThatAppeared');
    
    

    如果您不熟悉 DOM 选择器,可以阅读 herehere。它们功能强大且易于使用。

    更新 - 自定义等待谓词。

    如果我们总是知道长度...

    await myButton.click();
    await page.waitFor(() => document.querySelectorAll('ul.specialList li').length > 5);
    

    如果我们知道长度会增加

    const listSize = await page.evaluate(() => document.querySelectorAll('ul.specialList li').length);
    await myButton.click();
    await page.waitFor(() => document.querySelectorAll('ul.specialList li').length > listSize);
    

    【讨论】:

    • 嗨!获取的数据将更新一个已经非空的
    • 列表,所以恐怕我不能依赖特定选择器的存在......也许等待列表改变大小?但是怎么做呢?
  • 嗯。你能用DOM的点击前状态和点击后状态的相关sn-p更新问题吗?我也许可以在这些细节方面提供更多帮助。
  • 【解决方案2】:

    嗯,有点破解,但目前没有找到更好的解决方案。 基本上我是在点击按钮之前和之后比较特定 li 元素的数量,以验证何时加载了新数据。

    const wait = time => new Promise(resolve => setTimeout(resolve, time))
    
    let data = await page.evaluate(_ => document.querySelectorAll("li.className").length) 
    
    let isDataLoaded = false
    await page.click("#myButton")
    
    while(!isDataLoaded) {
        if (data.length !== await.page.evaluate(_ => document.querySelectorAll("li.className").length)) {
            isDataLoaded = true
        }
        await wait(100)
    }
    
    // new data should be loaded and rendered now in the page
    // [...]
    

    【讨论】:

    • 代替那个while循环,你能像我上一个例子那样使用waitFor吗?
    • await page.waitFor(() => document.querySelectorAll('li.className').length != listSize);
    • 我认为您使用了不正确的语法: await page.waitFor(listSize => document.querySelectorAll('li.className').length > listSize, {}, listSize) 这有效,但从我的测试相对于 while 解决方案来说速度较慢
    • 在我的示例中,我将变量称为 listSize。你称它为data。是这个问题吗?
    • 等待 page.waitFor(() => document.querySelectorAll('li.className').length !== data);
    【解决方案3】:

    首先await Promise.all某种并发,如果你需要点击然后等待

    分割
    await page.click('#selector');
    const finalResponse = await page.waitForResponse(response => response.url() === 'https://example.com' && response.status() === 200);
    return finalResponse.ok();
    

    并成为noted

    这会在页面导航到新 URL 或重新加载时解决。

    【讨论】:

    • @Faltesek 我修正了我的错字,请删除你的减号。
    • @Tom Faltesek 为什么我的回答需要你的-1?我试图帮助你尝试巨魔?
    • 不是想骗你。只是指出 OP 声明导航和 URL 确实 改变。所以你的解决方案不会有帮助。
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签