mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:18:13 +00:00
LibWeb: Store Promise::wait_for_all state in a JS-heap allocated object
The one current caller of this function always defers microtask checkpoints before calling wait_for_all, ensuring that the promise accept/reject handlers will always be called later in the Web event loop processing. We need to store all the state for the closures in a heap allocated object with HeapFunctions to keep it around while there are still promises to resolve.
This commit is contained in:
parent
346eb02659
commit
3441b37de5
3 changed files with 57 additions and 28 deletions
|
@ -22,6 +22,7 @@
|
|||
#include <LibWeb/HTML/NavigationHistoryEntry.h>
|
||||
#include <LibWeb/HTML/NavigationTransition.h>
|
||||
#include <LibWeb/HTML/Scripting/ExceptionReporter.h>
|
||||
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
|
||||
#include <LibWeb/HTML/TraversableNavigable.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
|
@ -1068,7 +1069,7 @@ bool Navigation::inner_navigate_event_firing_algorithm(
|
|||
|
||||
// 31. Prepare to run script given navigation's relevant settings object.
|
||||
// NOTE: There's a massive spec note here
|
||||
relevant_settings_object(*this).prepare_to_run_script();
|
||||
TemporaryExecutionContext execution_context { relevant_settings_object(*this) };
|
||||
|
||||
// 32. If event's interception state is not "none":
|
||||
if (event->interception_state() != NavigateEvent::InterceptionState::None) {
|
||||
|
@ -1117,11 +1118,6 @@ bool Navigation::inner_navigate_event_firing_algorithm(
|
|||
for (auto const& handler : event->navigation_handler_list()) {
|
||||
// 1. Append the result of invoking handler with an empty arguments list to promisesList.
|
||||
auto result = WebIDL::invoke_callback(handler, {});
|
||||
if (result.is_abrupt()) {
|
||||
// FIXME: https://github.com/whatwg/html/issues/9774
|
||||
report_exception(result.release_error(), realm);
|
||||
continue;
|
||||
}
|
||||
// This *should* be equivalent to converting a promise to a promise capability
|
||||
promises_list.append(WebIDL::create_resolved_promise(realm, result.value().value()));
|
||||
}
|
||||
|
@ -1139,9 +1135,12 @@ bool Navigation::inner_navigate_event_firing_algorithm(
|
|||
|
||||
// 4. Wait for all of promisesList, with the following success steps:
|
||||
WebIDL::wait_for_all(
|
||||
realm, promises_list, [&](JS::MarkedVector<JS::Value> const&) -> void {
|
||||
realm, promises_list, [event, this, api_method_tracker](auto const&) -> void {
|
||||
|
||||
// FIXME: Spec issue: Event's relevant global objects' *associated document*
|
||||
// 1. If event's relevant global object is not fully active, then abort these steps.
|
||||
auto& relevant_global_object = verify_cast<HTML::Window>(HTML::relevant_global_object(*event));
|
||||
auto& realm = event->realm();
|
||||
if (!relevant_global_object.associated_document().is_fully_active())
|
||||
return;
|
||||
|
||||
|
@ -1170,12 +1169,14 @@ bool Navigation::inner_navigate_event_firing_algorithm(
|
|||
m_transition = nullptr;
|
||||
|
||||
// 9. If apiMethodTracker is non-null, then resolve the finished promise for apiMethodTracker.
|
||||
if (api_method_tracker)
|
||||
if (api_method_tracker != nullptr)
|
||||
resolve_the_finished_promise(*api_method_tracker); },
|
||||
// and the following failure steps given reason rejectionReason:
|
||||
[&](JS::Value rejection_reason) -> void {
|
||||
[event, this, api_method_tracker](JS::Value rejection_reason) -> void {
|
||||
// FIXME: Spec issue: Event's relevant global objects' *associated document*
|
||||
// 1. If event's relevant global object is not fully active, then abort these steps.
|
||||
auto& relevant_global_object = verify_cast<HTML::Window>(HTML::relevant_global_object(*event));
|
||||
auto& realm = event->realm();
|
||||
if (!relevant_global_object.associated_document().is_fully_active())
|
||||
return;
|
||||
|
||||
|
@ -1213,18 +1214,18 @@ bool Navigation::inner_navigate_event_firing_algorithm(
|
|||
m_transition = nullptr;
|
||||
|
||||
// 9. If apiMethodTracker is non-null, then reject the finished promise for apiMethodTracker with rejectionReason.
|
||||
if (api_method_tracker)
|
||||
if (api_method_tracker != nullptr)
|
||||
reject_the_finished_promise(*api_method_tracker, rejection_reason);
|
||||
});
|
||||
}
|
||||
|
||||
// 34. Otherwise, if apiMethodTracker is non-null, then clean up apiMethodTracker.
|
||||
else if (api_method_tracker) {
|
||||
else if (api_method_tracker != nullptr) {
|
||||
clean_up(*api_method_tracker);
|
||||
}
|
||||
|
||||
// 35. Clean up after running script given navigation's relevant settings object.
|
||||
relevant_settings_object(*this).clean_up_after_running_script();
|
||||
// Handled by TemporaryExecutionContext destructor from step 31
|
||||
|
||||
// 36. If event's interception state is "none", then return true.
|
||||
// 37. Return false.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue