多线程
介绍
¥Introduction
Playwright Java 不是线程安全的,也就是说,它的所有方法以及它创建的所有对象(例如 BrowserContext、Browser、Page 等)上的方法都应该在创建 Playwright 对象的同一线程中调用,或者应该实现适当的同步,以确保在任何给定时间只有一个线程调用 Playwright 方法。话虽如此,可以在各自的线程上创建多个 Playwright 实例。
¥Playwright Java is not thread safe, i.e. all its methods as well as methods on all objects created by it (such as BrowserContext, Browser, Page etc.) are expected to be called on the same thread where the Playwright object was created or proper synchronization should be implemented to ensure only one thread calls Playwright methods at any given time. Having said that it's okay to create multiple Playwright instances each on its own thread.
以下是一个在各自线程上创建三个 Playwright 实例的示例。每个实例都会启动自己的浏览器进程并针对其运行测试。
¥Here is an example where three playwright instances are created each on its own thread. Each instance launches its own browser process and runs the test against it.
package org.example;
import com.microsoft.playwright.*;
import java.nio.file.Paths;
import static java.util.Arrays.asList;
public class PlaywrightThread extends Thread {
private final String browserName;
private PlaywrightThread(String browserName) {
this.browserName = browserName;
}
public static void main(String[] args) throws InterruptedException {
// Create separate playwright thread for each browser.
for (String browserName: asList("chromium", "webkit", "firefox")) {
Thread thread = new PlaywrightThread(browserName);
thread.start();
}
}
@Override
public void run() {
try (Playwright playwright = Playwright.create()) {
BrowserType browserType = getBrowserType(playwright, browserName);
Browser browser = browserType.launch();
Page page = browser.newPage();
page.navigate("https://playwright.nodejs.cn/");
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("user-agent-" + browserName + ".png")));
}
}
private static BrowserType getBrowserType(Playwright playwright, String browserName) {
switch (browserName) {
case "chromium":
return playwright.chromium();
case "webkit":
return playwright.webkit();
case "firefox":
return playwright.firefox();
default:
throw new IllegalArgumentException();
}
}
}
同步 API 和事件调度
¥Synchronous API and event dispatching
在同步 Playwright API 中,所有事件仅在 Playwright 运行其消息循环时才会调度。当你调用任何 API 方法时,都会自动执行此操作;如果堆栈中没有活动的 Playwright 调用,则不会执行此操作。如果你需要等待某个事件,最好的方法是通过 waitFor*
方法之一。
¥In the synchronous Playwright API all events are dispatched only when Playwright is running its message loop. This happens automatically when you call any of the API methods and doesn't happen if there are no active Playwright calls on the stack. If you need to wait for an event the best way to do this is via one of the waitFor*
methods.
Page.waitForTimeout() vs. Thread.sleep()
同步 API 的一个后果是,如果你出于任何原因调用 Thread.sleep()
,则在线程休眠期间不会触发任何事件。如果你希望在程序运行时调度来自浏览器的事件,
¥One consequence of the synchronous API is that if you for whatever reason call Thread.sleep()
no events will be fired while the thread is sleeping. If you want events from the browser to be dispatched while the program
执行暂停时使用 Page.waitForTimeout() 或 Frame.waitForTimeout():
¥execution is paused use Page.waitForTimeout() or Frame.waitForTimeout():
page.onResponse(response -> System.out.println(response.url()));
page.navigate("https://playwright.nodejs.cn");
System.out.println("-- did navigate --");
// Block current thread for 60s and ensure the events are dispatched.
page.waitForTimeout(60_000);