1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 13:35:00 +00:00

LibWeb: Make <script src> loads partially async (by following the spec)

Instead of firing up a network request and synchronously blocking for it
to finish via a nested event loop, we now start an asynchronous request
when encountering <script src>.

Once the script load finishes (or fails), it gets executed at one of the
synchronization points in the HTML parser.

This solves some long-standing issues with random unexpected events
getting dispatched in the middle of parsing.
This commit is contained in:
Andreas Kling 2021-09-20 17:06:10 +02:00
parent e11ae33c66
commit c34da16089
3 changed files with 40 additions and 22 deletions

View file

@ -291,9 +291,8 @@ void HTMLScriptElement::prepare_script()
// Fetch a classic script given url, settings object, options, classic script CORS setting, and encoding.
auto request = LoadRequest::create_for_url_on_page(url, document().page());
// FIXME: This load should be made asynchronous and the parser should spin an event loop etc.
m_script_filename = url.to_string();
ResourceLoader::the().load_sync(
ResourceLoader::the().load(
request,
[this, url](auto data, auto&, auto) {
if (data.is_null()) {
@ -310,6 +309,8 @@ void HTMLScriptElement::prepare_script()
},
[this](auto&, auto) {
m_failed_to_load = true;
dbgln("HONK! Failed to load script, but ready nonetheless.");
script_became_ready();
});
} else if (m_script_type == ScriptType::Module) {
// FIXME: -> "module"
@ -374,21 +375,34 @@ void HTMLScriptElement::prepare_script()
// Add the element to the end of the list of scripts that will execute in order as soon as possible associated with the element's preparation-time document.
m_preparation_time_document->add_script_to_execute_as_soon_as_possible({}, *this);
// FIXME: When the script is ready, run the following steps:
// When the script is ready, run the following steps:
when_the_script_is_ready([this] {
// 1. If the element is not now the first element in the list of scripts
// that will execute in order as soon as possible to which it was added above,
// then mark the element as ready but return without executing the script yet.
if (this != &m_preparation_time_document->scripts_to_execute_as_soon_as_possible().first()) {
m_script_ready = true;
return;
}
// FIXME: 1. If the element is not now the first element in the list of scripts
// that will execute in order as soon as possible to which it was added above,
// then mark the element as ready but return without executing the script yet.
for (;;) {
// 2. Execution: Execute the script block corresponding to the first script element
// in this list of scripts that will execute in order as soon as possible.
m_preparation_time_document->scripts_to_execute_as_soon_as_possible().first().execute_script();
// FIXME: 2. Execution: Execute the script block corresponding to the first script element
// in this list of scripts that will execute in order as soon as possible.
//
// FIXME: 3. Remove the first element from this list of scripts that will execute in order
// as soon as possible.
//
// FIXME: 4. If this list of scripts that will execute in order as soon as possible is still
// not empty and the first entry has already been marked as ready, then jump back
// to the step labeled execution.
// 3. Remove the first element from this list of scripts that will execute in order
// as soon as possible.
m_preparation_time_document->scripts_to_execute_as_soon_as_possible().take_first();
// 4. If this list of scripts that will execute in order as soon as possible is still
// not empty and the first entry has already been marked as ready, then jump back
// to the step labeled execution.
if (!m_preparation_time_document->scripts_to_execute_as_soon_as_possible().is_empty() && m_preparation_time_document->scripts_to_execute_as_soon_as_possible().first().m_script_ready)
continue;
break;
}
});
}
// -> If the script's type is "classic", and the element has a src attribute
@ -399,6 +413,8 @@ void HTMLScriptElement::prepare_script()
m_preparation_time_document->add_script_to_execute_as_soon_as_possible({}, *this);
// FIXME: When the script is ready, execute the script block and then remove the element
// from the set of scripts that will execute as soon as possible.
TODO();
}
// FIXME: -> If the element does not have a src attribute, and the element is "parser-inserted",