A JavaFX webengine loads asynchronously per implementation. Any listener to the loadworker's stateproperty receives callback on the JavaFX thread. This thread also runs your UI, which is why you should NEVER block the JavaFX thread. In event based UI systems such as JavaFX, if you want to do some heavy work, you would do this in your own thread. Never, ever block the JavaFX thread.
The reason I'm answering is because I actually have a similar yet different situation in which I do need the load to be synchronous. My first idea was to wrap the load in my own thread and make that block, but the load operation needs to be called from the JavaFX thread. However, I figured out a way around this obstacle:
First I start a new thread in which I declare a semaphore (with 0 permits) from where I launch a Platform.runLater(...) that initiates an engine, adds a listener to the stateproperty and loads a URL, followed by trying to aquire the semaphore. This blocks, because the semaphore has no permits. In the listener's callback, I start another new thread in which I do my heavy work and from there I set some global data variable, after which I release the semaphore. This terminates my latter new thread and then informs the former new thread that the data is loaded so it may continue. This never blocks the JavaFX thread either.
When wrapping that in a function, you can emulate a synchronous load operation, but you should be cautious when using it: only call the function from outside the JavaFX thread. However, that makes perfect sense, because you should never be calling a synchronous (aka blocking) load on the JavaFX thread.