页面不会等待其他页面完成任务再继续

L.

所以这是代码片段:

    for (let item of items)
    {
        await page.waitFor(10000)
        await page.click("#item_"+item)
        await page.click("#i"+item)

        let pages = await browser.pages()
        let tempPage = pages[pages.length-1]

        await tempPage.waitFor("a.orange", {timeout: 60000, visible: true})
        await tempPage.click("a.orange")

        counter++
    }

pagetempPage是两个不同的页面。

发生的情况是page等待10秒钟,然后单击一些东西,这将打开第二页。

应该发生的是,tempPage等待一个元素,单击它,然后页面应该等待10秒钟,然后再重新进行操作。

但是,实际发生的是page等待10秒钟,单击内容,然后开始等待10秒钟,而无需等待tempPage完成其任务。

这是一个错误,还是我误会了什么?我应该如何解决这个问题,以便当for循环再次循环时,只有在tempPage单击后才可以。

路易

通常,在“完成其任务”await tempPage.click("a.orange")之前,您不能依靠暂停执行tempPage对于同步执行的超简单代码,它可能会起作用。但是总的来说,您不能依靠它。

如果单击触发了Ajax操作,或者启动了CSS动画,或者启动了无法立即计算的计算,或者打开了新页面等,则您等待的结果是异步的,并且该.click方法将不等待这个异步操作完成。

你能做什么?在某些情况下,您可能可以插入页面上正在运行的代码,并等待某些对您而言重要的事件。例如,如果您想等待Ajax操作完成并且页面上的代码使用jQuery,则可以使用它ajaxComplete来检测操作何时完成。如果无法挂接到任何事件系统以检测操作何时完成,则可能需要轮询页面以等待操作已完成的证据。

这是显示问题的示例:

const puppeteer = require('puppeteer');

function getResults(page) {
    return page.evaluate(() => ({
        clicked: window.clicked,
        asynchronousResponse: window.asynchronousResponse,
    }));
}

puppeteer.launch().then(async browser => {
    const page = await browser.newPage();
    await page.goto("https://example.com");
    // We add a button to the page that will click later.
    await page.evaluate(() => {
        const button = document.createElement("button");
        button.id = "myButton";
        button.textContent = "My Button";
        document.body.appendChild(button);
        window.clicked = 0;
        window.asynchronousResponse = 0;
        button.addEventListener("click", () => {
            // Synchronous operation
            window.clicked++;

            // Asynchronous operation.
            setTimeout(() => {
                window.asynchronousResponse++;
            }, 1000);
        });
    });

    console.log("before clicks", await getResults(page));

    const button = await page.$("#myButton");
    await button.click();
    await button.click();
    console.log("after clicks", await getResults(page));

    await page.waitForFunction(() => window.asynchronousResponse === 2);
    console.log("after wait", await getResults(page));

    await browser.close();
});

setTimeout代码模拟了由点击启动的任何类型的异步操作。

运行此代码时,您会在控制台上看到:

before click { clicked: 0, asynchronousResponse: 0 }
after click { clicked: 2, asynchronousResponse: 0 }
after wait { clicked: 2, asynchronousResponse: 2 }

您会看到clicked两次单击会立即将其增加两次。但是,需要一段时间才能asynchronousResponse递增。该语句await page.waitForFunction(() => window.asynchronousResponse === 2)轮询页面,直到实现我们等待的条件为止。


您在评论中提到该按钮正在关闭选项卡。打开和关闭选项卡是异步操作。这是一个例子:

puppeteer.launch().then(async browser => {
    let pages = await browser.pages();
    console.log("number of pages", pages.length);
    const page = pages[0];
    await page.goto("https://example.com");
    await page.evaluate(() => {
        window.open("https://example.com");
    });

    do {
        pages = await browser.pages();
        // For whatever reason, I need to have this here otherwise
        // browser.pages() always returns the same value. And the loop
        // never terminates.
        await page.evaluate(() => {});
        console.log("number of pages after evaluating open", pages.length);
    } while (pages.length === 1);

    let tempPage = pages[pages.length - 1];

    // Add a button that will close the page when we click it.
    tempPage.evaluate(() => {
        const button = document.createElement("button");
        button.id = "myButton";
        button.textContent = "My Button";
        document.body.appendChild(button);
        window.clicked = 0;
        window.asynchronousResponse = 0;
        button.addEventListener("click", () => {
            window.close();
        });
    });

    const button = await tempPage.$("#myButton");
    await button.click();

    do {
        pages = await browser.pages();
        // For whatever reason, I need to have this here otherwise
        // browser.pages() always returns the same value. And the loop
        // never terminates.
        await page.evaluate(() => {});
        console.log("number of pages after click", pages.length);
    } while (pages.length > 1);

    await browser.close();
});

当我运行上面的代码时,我得到:

number of pages 1
number of pages after evaluating open 1
number of pages after evaluating open 1
number of pages after evaluating open 2
number of pages after click 2
number of pages after click 1

您可以看到它花了一点时间window.open()window.close()产生了可察觉的效果。


在您的评论中,您还写道:

我以为await基本上是将异步功能变成了同步功能

我不会说它将异步功能转变为同步功能。它使当前代码等待异步操作的承诺得到解决或拒绝。但是,对于当前的问题而言,更重要的是,问题是您有两个执行JavaScript代码的虚拟机:运行Node的程序puppeteer和控制浏览器的脚本,以及拥有自己的JavaScript虚拟机的浏览器本身。您在“节点”端使用的任何await内容都只会影响“节点”代码:它与浏览器中运行的代码无关。

当您看到类似的内容时,可能会造成混淆await page.evaluate(() => { some code; })它看起来像是全部,并且全部在同一虚拟机中执行,但事实并非如此。puppeteer接受传递给的参数.evaluate,对其进行序列化,然后将其发送到执行它的浏览器。尝试await page.evaluate(() => { button.click(); });在之后的脚本中添加类似内容const button = ...像这样:

const button = await tempPage.$("#myButton");
await button.click();
await page.evaluate(() => { button.click(); });

在脚本中,button在之前定义了page.evaluate,但是由于未在浏览器端定义,因此运行ReferenceError会得到一个page.evaluatebutton

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

等待下载完成,然后再开始其他任务

Scala脚本等待mongo完成任务

Javascript:打开其他页面并继续操作

JS - 在继续之前等待其他功能完成其工作

Javascript Async / Await 完成任务并最终做其他事情

在完成任务对象很长时间之后是否还有其他缺点?

等待页面转换完成

烧瓶-在等待任务完成时使用javascript显示加载页面

等待与task.Result相同的已完成任务?

等待直到使用Selenium WebDriver for python完成任务

等待RunOnUIThread完成并继续执行其余任务

如何等待任务的完成及其继续?

等待FileReader完成后再继续

完成html中的视频后,转到其他页面

ExecutorService并在关闭后等待其他任务完成时接受新任务

调用者线程如何等待ScheduledExecutorService下的任务定期完成任务

奖励用户完成任务

选中时表分页不会转到其他页面

多线程-仅在所有线程完成任务后才继续

等待任务完成而不会阻塞UI线程

Azure 函数不会“等待”任务完成

其他任务完成时通知任务

主线程不会等待用户完成他们的任务,用户反应

等待直到通过Python在远程计算机上完成任务

在没有异步的情况下使用等待来完成任务

成功完成任务后,如何通过“输出变量”部分或Azure devops中的某些其他方法更新管道变量

如何使用shell脚本运行jar并等待其完成然后执行其他任务

在做任何其他事情之前等待一个方法任务完成

如果页面是通过其他页面的链接加载的,则Rails表单不会提交