java - 同步一系列异步调用

标签 java webview javafx

我正在使用 JavaFX 的 WebView解析网站。该网站包含一堆链接 - 我需要按照给定的顺序单独打开每个链接,并从每个链接中检索一条信息。

为了确保 WebView已加载整个网站,我正在听changed事件WebEngine等待newState == Worker.State.SUCCEEDED 。问题是这个调用是异步的。当我打电话webEngine.load(firstAddress);时,代码立即返回,在加载此页面之前,我的代码将调用另一个 webEngine.load(secondAddress); ,等等。

我理解为什么这样做(为什么异步比同步更好),但我是Java初学者,我不确定这个问题的最佳解决方案是什么。我以某种方式了解多线程和其他东西,所以我已经尝试过信号量( CountDownLatch 类)。但代码卡在await上我不确定我做错了什么。

有人可以告诉我如何以正确的方式完成它吗?也许有一些通用模式如何应对这样的场景?

我想要实现的伪代码:

WebEngine webEngine = new WebEngine();
webEngine.loadPage("http://www.something.com/list-of-cars");
webEngine.waitForThePageToLoad(); // I need an equivalent of this. In the real code, this is done asynchronously as a callback
// ... some HTML parsing or DOM traversing ...
List<String> allCarsOnTheWebsite = webEngine.getDocument()....getChildNodes()...;
// allCarsOnTheWebsite contains URLs to the pages I want to analyze

for (String url : allCarsOnTheWebsite)
{
    webEngine.loadPage(url);
    webEngine.waitForThePageToLoad(); // same as in line 3

    String someDataImInterestedIn = webEngine.getDocument()....getChildNodes()...Value();
    System.out.println(url + " : " + someDataImInterestedIn);
}

System.out.println("Done, all cars have been analyzed");

最佳答案

您应该使用在页面加载时调用的监听器,而不是阻塞直到完成。

类似于:

WebEngine webEngine = new WebEngine();
ChangeListener<State> initialListener = new ChangeListener<State>() {
    @Override
    public void changed(ObservableValue<? extends State> obs, State oldState, State newState) {
        if (newState == State.SUCCEEDED) {
            webEngine.getLoadWorker().stateProperty().removeListener(this);
            List<String> allCarsOnTheWebsite = webEngine.getDocument()... ;
            loadPagesConsecutively(allCarsOnTheWebsite, webEngine);
        }
    }
};
webEngine.getLoadWorker().addListener(initialListener);      
webEngine.loadPage("http://www.something.com/list-of-cars");

// ...

private void loadPagesConsecutively(List<String> pages, WebEngine webEngine) {
    LinkedList<String> pageStack = new LinkedList<>(pages);
    ChangeListener<State> nextPageListener = new ChangeListener<State>() {
        @Override
        public void changed(ObservableValue<? extends State> obs, State oldState, State newState) {
            if (newState == State.SUCCEEDED ) {
                // process current page data
                // ...
                if (pageStack.isEmpty()) {
                    webEngine.getLoadWorker().stateProperty().removeListener(this);
                } else {
                    // load next page:
                    webEngine.load(pageStack.pop());
                }
            }               
        }
    };
    webEngine.getLoadWorker().stateProperty().addListener(nextPageListener);

    // load first page (assumes pages is not empty):
    webEngine.load(pageStack.pop());
}

关于java - 同步一系列异步调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27494048/

相关文章:

java - 将相同的对象存储在不同的数组中

java - 谷歌地图与安卓

javafx - JavaFX 应用程序中的 "java.lang.IllegalStateException: Location is not set"

android - 如何在 Android 的 Webview 中加载文本?

JavaFX WebView 不加载页面

java - 将数据动态添加到 LineChart JavaFX

java - API返回不完整的JSON文件

java - 使用带有连接字符分隔符的收集器

java - Spring Boot - 缓存不起作用,如何正确设置缓存?

javascript - 即使使用 setJavascriptEnabled(true) 和 WebChromeClient,Android webview 也会跳过 javascript