diff --git a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp index f5590ddf32..92e30392ca 100644 --- a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp +++ b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -181,4 +182,89 @@ void mark_promise_as_handled(Promise const& promise) promise_object->set_is_handled(); } +// https://webidl.spec.whatwg.org/#wait-for-all +void wait_for_all(JS::Realm& realm, JS::MarkedVector> const& promises, JS::SafeFunction const&)> success_steps, JS::SafeFunction failure_steps) +{ + // FIXME: Fix spec typo, fullfilled --> fulfilled + // 1. Let fullfilledCount be 0. + size_t fulfilled_count = 0; + + // 2. Let rejected be false. + auto rejected = false; + + // 3. Let rejectionHandlerSteps be the following steps given arg: + auto rejection_handler_steps = [&rejected, failure_steps = move(failure_steps)](JS::VM& vm) -> JS::ThrowCompletionOr { + // 1. If rejected is true, abort these steps. + if (rejected) + return JS::js_undefined(); + + // 2. Set rejected to true. + rejected = true; + + // 3. Perform failureSteps given arg. + failure_steps(vm.argument(0)); + + return JS::js_undefined(); + }; + + // 4. Let rejectionHandler be CreateBuiltinFunction(rejectionHandlerSteps, « »): + auto rejection_handler = JS::NativeFunction::create(realm, move(rejection_handler_steps), 1, ""); + + // 5. Let total be promises’s size. + auto total = promises.size(); + + // 6. If total is 0, then: + if (total == 0) { + // 1. Queue a microtask to perform successSteps given « ». + HTML::queue_a_microtask(nullptr, [&realm, success_steps = move(success_steps)] { + success_steps(JS::MarkedVector { realm.heap() }); + }); + + // 2. Return. + return; + } + + // 7. Let index be 0. + auto index = 0; + + // 8. Let result be a list containing total null values. + auto result = JS::MarkedVector(realm.heap()); + result.ensure_capacity(total); + for (size_t i = 0; i < total; ++i) + result.unchecked_append(JS::js_null()); + + // 9. For each promise of promises: + for (auto const& promise : promises) { + // 1. Let promiseIndex be index. + auto promise_index = index; + + // FIXME: This should be fulfillmentHandlerSteps + // 2. Let fulfillmentHandler be the following steps given arg: + auto fulfillment_handler_steps = [&](JS::VM& vm) -> JS::ThrowCompletionOr { + auto arg = vm.argument(0); + + // 1. Set result[promiseIndex] to arg. + result[promise_index] = arg; + + // 2. Set fullfilledCount to fullfilledCount + 1. + ++fulfilled_count; + + // 3. If fullfilledCount equals total, then perform successSteps given result. + if (fulfilled_count == total) + success_steps(result); + + return JS::js_undefined(); + }; + + // 3. Let fulfillmentHandler be CreateBuiltinFunction(fulfillmentHandler, « »): + auto fulfillment_handler = JS::NativeFunction::create(realm, move(fulfillment_handler_steps), 1, ""); + + // 4. Perform PerformPromiseThen(promise, fulfillmentHandler, rejectionHandler). + static_cast(*promise->promise()).perform_then(fulfillment_handler, rejection_handler, nullptr); + + // 5. Set index to index + 1. + ++index; + } +} + } diff --git a/Userland/Libraries/LibWeb/WebIDL/Promise.h b/Userland/Libraries/LibWeb/WebIDL/Promise.h index 7e0e8141c8..ddc7ebe711 100644 --- a/Userland/Libraries/LibWeb/WebIDL/Promise.h +++ b/Userland/Libraries/LibWeb/WebIDL/Promise.h @@ -29,5 +29,6 @@ JS::NonnullGCPtr react_to_promise(Promise const&, Optional upon_fulfillment(Promise const&, ReactionSteps); JS::NonnullGCPtr upon_rejection(Promise const&, ReactionSteps); void mark_promise_as_handled(Promise const&); +void wait_for_all(JS::Realm&, JS::MarkedVector> const& promises, JS::SafeFunction const&)> success_steps, JS::SafeFunction failure_steps); }