diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index 4da167dda76..f6b4132d74b 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -35,10 +35,11 @@ use script_bindings::conversions::SafeToJSValConvertible; use crate::dom::bindings::conversions::root_from_object; use crate::dom::bindings::error::{Error, ErrorToJsval}; use crate::dom::bindings::reflector::{DomGlobal, DomObject, MutDomObject, Reflector}; -use crate::dom::bindings::root::AsHandleValue; +use crate::dom::bindings::root::{AsHandleValue, DomRoot}; use crate::dom::bindings::settings_stack::AutoEntryScript; use crate::dom::globalscope::GlobalScope; use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler}; +use crate::microtask::{Microtask, MicrotaskRunnable}; use crate::realms::{AlreadyInRealm, InRealm, enter_realm}; use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; use crate::script_thread::ScriptThread; @@ -490,6 +491,27 @@ impl Callback for WaitForAllRejectionHandler { } } +/// The microtask for performing successSteps given « » in +/// . +#[derive(JSTraceable, MallocSizeOf)] +pub(crate) struct WaitForAllSuccessStepsMicrotask { + global: DomRoot, + + #[ignore_malloc_size_of = "Closure is hard"] + #[no_trace] + success_steps: WaitForAllSuccessSteps, +} + +impl MicrotaskRunnable for WaitForAllSuccessStepsMicrotask { + fn handler(&self, _can_gc: CanGc) { + (self.success_steps)(vec![]); + } + + fn enter_realm(&self) -> JSAutoRealm { + enter_realm(&*self.global) + } +} + /// #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn wait_for_all( @@ -521,8 +543,19 @@ pub(crate) fn wait_for_all( // Note: done using the len of result. // If total is 0, then: - // Queue a microtask to perform successSteps given « ». - // TODO: #37259 + if promises.is_empty() { + // Queue a microtask to perform successSteps given « ». + global.microtask_queue().enqueue( + Microtask::WaitForAllSuccessSteps(WaitForAllSuccessStepsMicrotask { + global: DomRoot::from_ref(global), + success_steps, + }), + cx, + ); + + // Return. + return; + } // Let index be 0. // Note: done with `enumerate` below. @@ -594,26 +627,16 @@ pub(crate) fn wait_for_all_promise( failure_promise.reject_native(&reason, can_gc); }); - if promises.is_empty() { - // Note: part of `wait_for_all`. - // Done here by using `resolve_native`. - // TODO: #37259 - // If total is 0, then: - // Queue a microtask to perform successSteps given « ». - let empty_list: Vec = vec![]; - promise.resolve_native(&empty_list, can_gc); - } else { - // Wait for all with promises, given successSteps and failureSteps. - wait_for_all( - cx, - global, - promises, - success_steps, - failure_steps, - realm, - can_gc, - ); - } + // Wait for all with promises, given successSteps and failureSteps. + wait_for_all( + cx, + global, + promises, + success_steps, + failure_steps, + realm, + can_gc, + ); // Return promise. promise diff --git a/components/script/microtask.rs b/components/script/microtask.rs index f1c49f7ba18..d939bbd7284 100644 --- a/components/script/microtask.rs +++ b/components/script/microtask.rs @@ -23,6 +23,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::html::htmlimageelement::ImageElementMicrotask; use crate::dom::html::htmlmediaelement::MediaElementMicrotask; use crate::dom::mutationobserver::MutationObserver; +use crate::dom::promise::WaitForAllSuccessStepsMicrotask; use crate::realms::enter_realm; use crate::script_runtime::{CanGc, JSContext, notify_about_rejected_promises}; use crate::script_thread::ScriptThread; @@ -43,6 +44,7 @@ pub(crate) enum Microtask { MediaElement(MediaElementMicrotask), ImageElement(ImageElementMicrotask), ReadableStreamTeeReadRequest(DefaultTeeReadRequestMicrotask), + WaitForAllSuccessSteps(WaitForAllSuccessStepsMicrotask), CustomElementReaction, NotifyMutationObservers, } @@ -141,16 +143,20 @@ impl MicrotaskQueue { let _realm = task.enter_realm(); task.handler(can_gc); }, + Microtask::ReadableStreamTeeReadRequest(ref task) => { + let _realm = task.enter_realm(); + task.handler(can_gc); + }, + Microtask::WaitForAllSuccessSteps(ref task) => { + let _realm = task.enter_realm(); + task.handler(can_gc); + }, Microtask::CustomElementReaction => { ScriptThread::invoke_backup_element_queue(can_gc); }, Microtask::NotifyMutationObservers => { MutationObserver::notify_mutation_observers(can_gc); }, - Microtask::ReadableStreamTeeReadRequest(ref task) => { - let _realm = task.enter_realm(); - task.handler(can_gc); - }, } } }