多线程
简介
Playwright Java 不是线程安全的,也就是说,它的所有方法以及由它创建的所有对象(如 BrowserContext、Browser、Page 等)上的方法,都应该在创建 Playwright 对象的同一线程中调用,或者应该实现适当的同步,以确保在任何给定时间只有一个线程调用 Playwright 方法。话虽如此,在各自的线程中创建多个 Playwright 实例是可行的。
以下是一个示例,其中在各自的线程中创建了三个 Playwright 实例。每个实例都会启动自己的浏览器进程并针对其运行测试。
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 {
// 为每个浏览器创建单独的 Playwright 线程。
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.dev/");
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 与事件派发
在同步的 Playwright API 中,所有事件仅在 Playwright 运行其消息循环时才会派发。当你调用任何 API 方法时,这会自动发生;如果调用栈上没有活跃的 Playwright 调用,则不会发生。如果你需要等待某个事件,最好的方法是使用 waitFor*
系列方法中的一个。
Page.waitForTimeout() 与 Thread.sleep()
同步 API 的一个结果是,无论出于何种原因,如果你调用 Thread.sleep()
,在线程睡眠期间不会触发任何事件。如果你希望在程序执行暂停时,浏览器中的事件仍能被派发,可以使用 Page.waitForTimeout() 或 Frame.waitForTimeout():
page.onResponse(response -> System.out.println(response.url()));
page.navigate("https://playwright.dev");
System.out.println("-- 已导航 --");
// 阻塞当前线程 60 秒,并确保事件被派发。
page.waitForTimeout(60_000);