Многопоточность
Введение
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 и обработка событий
В синхронном API Playwright все события обрабатываются только тогда, когда 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("-- did navigate --");
// Заблокируйте текущий поток на 60 секунд и убедитесь, что события обрабатываются.
page.waitForTimeout(60_000);