LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
/*
2024-04-09 07:02:15 +01:00
* Copyright ( c ) 2021 - 2024 , Linus Groh < linusg @ serenityos . org >
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
*/
2021-08-21 16:31:55 -04:00
# include <AK/Function.h>
2021-06-20 01:09:39 +01:00
# include <LibJS/Runtime/AbstractOperations.h>
2021-08-21 16:43:38 -04:00
# include <LibJS/Runtime/AggregateError.h>
2021-08-21 13:41:32 -04:00
# include <LibJS/Runtime/Array.h>
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
# include <LibJS/Runtime/Error.h>
2021-06-27 21:48:34 +02:00
# include <LibJS/Runtime/FunctionObject.h>
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
# include <LibJS/Runtime/GlobalObject.h>
2023-07-19 06:54:48 -04:00
# include <LibJS/Runtime/Iterator.h>
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
# include <LibJS/Runtime/Promise.h>
2022-10-02 10:59:22 +01:00
# include <LibJS/Runtime/PromiseCapability.h>
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
# include <LibJS/Runtime/PromiseConstructor.h>
2021-08-21 15:23:12 -04:00
# include <LibJS/Runtime/PromiseResolvingElementFunctions.h>
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
namespace JS {
2023-11-19 09:45:05 +01:00
JS_DEFINE_ALLOCATOR ( PromiseConstructor ) ;
2021-08-21 13:41:32 -04:00
// 27.2.4.1.1 GetPromiseResolve ( promiseConstructor ), https://tc39.es/ecma262/#sec-getpromiseresolve
2022-08-21 16:09:38 +01:00
static ThrowCompletionOr < Value > get_promise_resolve ( VM & vm , Value constructor )
2021-08-21 13:41:32 -04:00
{
VERIFY ( constructor . is_constructor ( ) ) ;
2021-11-14 00:33:16 +00:00
// 1. Let promiseResolve be ? Get(promiseConstructor, "resolve").
2022-08-21 14:00:56 +01:00
auto promise_resolve = TRY ( constructor . get ( vm , vm . names . resolve ) ) ;
2021-11-14 00:33:16 +00:00
// 2. If IsCallable(promiseResolve) is false, throw a TypeError exception.
2021-10-20 22:10:08 -04:00
if ( ! promise_resolve . is_function ( ) )
2023-08-09 08:49:02 +02:00
return vm . throw_completion < TypeError > ( ErrorType : : NotAFunction , promise_resolve . to_string_without_side_effects ( ) ) ;
2021-08-21 13:41:32 -04:00
2021-11-14 00:33:16 +00:00
// 3. Return promiseResolve.
2021-08-21 13:41:32 -04:00
return promise_resolve ;
}
2021-10-19 22:53:27 +03:00
using EndOfElementsCallback = Function < ThrowCompletionOr < Value > ( PromiseValueList & ) > ;
2021-10-20 22:55:17 -04:00
using InvokeElementFunctionCallback = Function < ThrowCompletionOr < Value > ( PromiseValueList & , RemainingElements & , Value , size_t ) > ;
2021-08-21 16:31:55 -04:00
2023-06-23 15:35:19 -04:00
static ThrowCompletionOr < Value > perform_promise_common ( VM & vm , IteratorRecord & iterator_record , Value constructor , PromiseCapability const & result_capability , Value promise_resolve , EndOfElementsCallback end_of_list , InvokeElementFunctionCallback invoke_element_function )
2021-08-21 13:41:32 -04:00
{
VERIFY ( constructor . is_constructor ( ) ) ;
VERIFY ( promise_resolve . is_function ( ) ) ;
2021-11-14 00:33:16 +00:00
// 1. Let values be a new empty List.
2024-11-14 06:13:46 +13:00
auto values = vm . heap ( ) . allocate < PromiseValueList > ( ) ;
2021-11-14 00:33:16 +00:00
// 2. Let remainingElementsCount be the Record { [[Value]]: 1 }.
2024-11-14 06:13:46 +13:00
auto remaining_elements_count = vm . heap ( ) . allocate < RemainingElements > ( 1 ) ;
2021-11-14 00:33:16 +00:00
// 3. Let index be 0.
2021-08-21 13:41:32 -04:00
size_t index = 0 ;
2021-11-14 00:33:16 +00:00
// 4. Repeat,
2021-08-21 13:41:32 -04:00
while ( true ) {
2024-02-01 14:53:28 -05:00
// a. Let next be ? IteratorStepValue(iteratorRecord).
auto next = TRY ( iterator_step_value ( vm , iterator_record ) ) ;
2021-08-21 13:41:32 -04:00
2024-02-01 14:53:28 -05:00
// b. If next is DONE, then
if ( ! next . has_value ( ) ) {
// i. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
// ii. If remainingElementsCount.[[Value]] = 0, then
2021-11-14 00:33:16 +00:00
if ( - - remaining_elements_count - > value = = 0 ) {
2024-02-01 14:53:28 -05:00
// 1-2. are handled in `end_of_list`
2021-10-20 22:55:17 -04:00
return TRY ( end_of_list ( * values ) ) ;
2021-11-14 00:33:16 +00:00
}
2024-02-01 14:53:28 -05:00
// iii. Return resultCapability.[[Promise]].
2022-10-02 12:11:30 +01:00
return result_capability . promise ( ) ;
2021-08-21 13:41:32 -04:00
}
2024-02-01 14:53:28 -05:00
// c. Append undefined to values.
2021-09-11 22:16:30 +02:00
values - > values ( ) . append ( js_undefined ( ) ) ;
2021-08-21 13:41:32 -04:00
2024-02-01 14:53:28 -05:00
// d. Let nextPromise be ? Call(promiseResolve, constructor, « next »).
auto next_promise = TRY ( call ( vm , promise_resolve . as_function ( ) , constructor , next . release_value ( ) ) ) ;
2021-08-21 13:41:32 -04:00
2024-02-01 14:53:28 -05:00
// e-l. are handled in `invoke_element_function`
2021-11-14 00:33:16 +00:00
2024-02-01 14:53:28 -05:00
// m. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] + 1.
2021-08-21 13:41:32 -04:00
+ + remaining_elements_count - > value ;
2024-02-01 14:53:28 -05:00
// n. Perform ? Invoke(nextPromise, "then", « ... »).
2021-10-20 22:55:17 -04:00
TRY ( invoke_element_function ( * values , * remaining_elements_count , next_promise , index ) ) ;
2021-11-14 00:33:16 +00:00
2024-02-01 14:53:28 -05:00
// o. Set index to index + 1.
2021-08-21 13:41:32 -04:00
+ + index ;
}
}
2021-08-21 16:31:55 -04:00
// 27.2.4.1.2 PerformPromiseAll ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseall
2023-06-23 15:35:19 -04:00
static ThrowCompletionOr < Value > perform_promise_all ( VM & vm , IteratorRecord & iterator_record , Value constructor , PromiseCapability const & result_capability , Value promise_resolve )
2021-08-21 16:31:55 -04:00
{
2022-08-21 16:09:38 +01:00
auto & realm = * vm . current_realm ( ) ;
2021-08-21 16:31:55 -04:00
return perform_promise_common (
2022-08-21 16:09:38 +01:00
vm , iterator_record , constructor , result_capability , promise_resolve ,
2021-10-19 22:53:27 +03:00
[ & ] ( PromiseValueList & values ) - > ThrowCompletionOr < Value > {
2022-05-02 20:54:39 +02:00
// 1. Let valuesArray be CreateArrayFromList(values).
2022-12-13 20:49:49 +00:00
auto values_array = Array : : create_from ( realm , values . values ( ) ) ;
2021-08-21 16:31:55 -04:00
2021-11-14 00:33:16 +00:00
// 2. Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »).
2022-10-02 12:11:30 +01:00
TRY ( call ( vm , * result_capability . resolve ( ) , js_undefined ( ) , values_array ) ) ;
2021-08-21 16:31:55 -04:00
2021-11-14 00:33:16 +00:00
// iv. Return resultCapability.[[Promise]].
2022-10-02 12:11:30 +01:00
return result_capability . promise ( ) ;
2021-08-21 16:31:55 -04:00
} ,
[ & ] ( PromiseValueList & values , RemainingElements & remaining_elements_count , Value next_promise , size_t index ) {
2021-11-14 00:33:16 +00:00
// j. Let steps be the algorithm steps defined in Promise.all Resolve Element Functions.
// k. Let length be the number of non-optional parameters of the function definition in Promise.all Resolve Element Functions.
2022-05-02 20:54:39 +02:00
// l. Let onFulfilled be CreateBuiltinFunction(steps, length, "", « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »).
2021-11-14 00:33:16 +00:00
// m. Set onFulfilled.[[AlreadyCalled]] to false.
// n. Set onFulfilled.[[Index]] to index.
// o. Set onFulfilled.[[Values]] to values.
// p. Set onFulfilled.[[Capability]] to resultCapability.
// q. Set onFulfilled.[[RemainingElements]] to remainingElementsCount.
2022-12-13 20:49:50 +00:00
auto on_fulfilled = PromiseAllResolveElementFunction : : create ( realm , index , values , result_capability , remaining_elements_count ) ;
2023-01-21 10:42:46 -05:00
on_fulfilled - > define_direct_property ( vm . names . name , PrimitiveString : : create ( vm , String { } ) , Attribute : : Configurable ) ;
2021-08-21 16:31:55 -04:00
2021-11-14 00:33:16 +00:00
// s. Perform ? Invoke(nextPromise, "then", « onFulfilled, resultCapability.[[Reject]] »).
2022-10-02 12:11:30 +01:00
return next_promise . invoke ( vm , vm . names . then , on_fulfilled , result_capability . reject ( ) ) ;
2021-08-21 16:31:55 -04:00
} ) ;
}
2021-08-21 17:00:48 -04:00
// 27.2.4.2.1 PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseallsettled
2023-06-23 15:35:19 -04:00
static ThrowCompletionOr < Value > perform_promise_all_settled ( VM & vm , IteratorRecord & iterator_record , Value constructor , PromiseCapability const & result_capability , Value promise_resolve )
2021-08-21 17:00:48 -04:00
{
2022-08-21 16:09:38 +01:00
auto & realm = * vm . current_realm ( ) ;
2021-08-21 17:00:48 -04:00
return perform_promise_common (
2022-08-21 16:09:38 +01:00
vm , iterator_record , constructor , result_capability , promise_resolve ,
2021-10-19 22:53:27 +03:00
[ & ] ( PromiseValueList & values ) - > ThrowCompletionOr < Value > {
2022-12-13 20:49:49 +00:00
auto values_array = Array : : create_from ( realm , values . values ( ) ) ;
2021-08-21 17:00:48 -04:00
2022-10-02 12:11:30 +01:00
TRY ( call ( vm , * result_capability . resolve ( ) , js_undefined ( ) , values_array ) ) ;
2021-08-21 17:00:48 -04:00
2022-10-02 12:11:30 +01:00
return result_capability . promise ( ) ;
2021-08-21 17:00:48 -04:00
} ,
[ & ] ( PromiseValueList & values , RemainingElements & remaining_elements_count , Value next_promise , size_t index ) {
2021-11-14 00:33:16 +00:00
// j. Let stepsFulfilled be the algorithm steps defined in Promise.allSettled Resolve Element Functions.
// k. Let lengthFulfilled be the number of non-optional parameters of the function definition in Promise.allSettled Resolve Element Functions.
2022-05-02 20:54:39 +02:00
// l. Let onFulfilled be CreateBuiltinFunction(stepsFulfilled, lengthFulfilled, "", « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »).
2021-11-14 00:33:16 +00:00
// m. Let alreadyCalled be the Record { [[Value]]: false }.
// n. Set onFulfilled.[[AlreadyCalled]] to alreadyCalled.
// o. Set onFulfilled.[[Index]] to index.
// p. Set onFulfilled.[[Values]] to values.
// q. Set onFulfilled.[[Capability]] to resultCapability.
// r. Set onFulfilled.[[RemainingElements]] to remainingElementsCount.
2022-12-13 20:49:50 +00:00
auto on_fulfilled = PromiseAllSettledResolveElementFunction : : create ( realm , index , values , result_capability , remaining_elements_count ) ;
2023-01-21 10:42:46 -05:00
on_fulfilled - > define_direct_property ( vm . names . name , PrimitiveString : : create ( vm , String { } ) , Attribute : : Configurable ) ;
2021-08-21 17:00:48 -04:00
2021-11-14 00:33:16 +00:00
// s. Let stepsRejected be the algorithm steps defined in Promise.allSettled Reject Element Functions.
// t. Let lengthRejected be the number of non-optional parameters of the function definition in Promise.allSettled Reject Element Functions.
2022-05-02 20:54:39 +02:00
// u. Let onRejected be CreateBuiltinFunction(stepsRejected, lengthRejected, "", « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »).
2021-11-14 00:33:16 +00:00
// v. Set onRejected.[[AlreadyCalled]] to alreadyCalled.
// w. Set onRejected.[[Index]] to index.
// x. Set onRejected.[[Values]] to values.
// y. Set onRejected.[[Capability]] to resultCapability.
// z. Set onRejected.[[RemainingElements]] to remainingElementsCount.
2022-12-13 20:49:50 +00:00
auto on_rejected = PromiseAllSettledRejectElementFunction : : create ( realm , index , values , result_capability , remaining_elements_count ) ;
2023-01-21 10:42:46 -05:00
on_rejected - > define_direct_property ( vm . names . name , PrimitiveString : : create ( vm , String { } ) , Attribute : : Configurable ) ;
2021-08-21 17:00:48 -04:00
2021-11-14 00:33:16 +00:00
// ab. Perform ? Invoke(nextPromise, "then", « onFulfilled, onRejected »).
2022-08-21 14:00:56 +01:00
return next_promise . invoke ( vm , vm . names . then , on_fulfilled , on_rejected ) ;
2021-08-21 17:00:48 -04:00
} ) ;
}
2021-08-21 16:43:38 -04:00
// 27.2.4.3.1 PerformPromiseAny ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseany
2023-06-23 15:35:19 -04:00
static ThrowCompletionOr < Value > perform_promise_any ( VM & vm , IteratorRecord & iterator_record , Value constructor , PromiseCapability & result_capability , Value promise_resolve )
2021-08-21 16:43:38 -04:00
{
2022-08-21 16:09:38 +01:00
auto & realm = * vm . current_realm ( ) ;
2021-08-21 16:43:38 -04:00
return perform_promise_common (
2022-08-21 16:09:38 +01:00
vm , iterator_record , constructor , result_capability , promise_resolve ,
2021-10-19 22:53:27 +03:00
[ & ] ( PromiseValueList & errors ) - > ThrowCompletionOr < Value > {
2021-11-14 00:33:16 +00:00
// 1. Let error be a newly created AggregateError object.
2022-12-13 20:49:49 +00:00
auto error = AggregateError : : create ( realm ) ;
2021-11-14 00:33:16 +00:00
2022-05-02 20:54:39 +02:00
// 2. Perform ! DefinePropertyOrThrow(error, "errors", PropertyDescriptor { [[Configurable]]: true, [[Enumerable]]: false, [[Writable]]: true, [[Value]]: CreateArrayFromList(errors) }).
2022-12-13 20:49:49 +00:00
auto errors_array = Array : : create_from ( realm , errors . values ( ) ) ;
2021-10-03 01:35:36 +01:00
MUST ( error - > define_property_or_throw ( vm . names . errors , { . value = errors_array , . writable = true , . enumerable = false , . configurable = true } ) ) ;
2021-08-21 16:43:38 -04:00
2021-11-14 00:33:16 +00:00
// 3. Return ThrowCompletion(error).
2021-10-19 22:53:27 +03:00
return throw_completion ( error ) ;
2021-08-21 16:43:38 -04:00
} ,
[ & ] ( PromiseValueList & errors , RemainingElements & remaining_elements_count , Value next_promise , size_t index ) {
2021-11-14 00:33:16 +00:00
// j. Let stepsRejected be the algorithm steps defined in Promise.any Reject Element Functions.
// k. Let lengthRejected be the number of non-optional parameters of the function definition in Promise.any Reject Element Functions.
2022-05-02 20:54:39 +02:00
// l. Let onRejected be CreateBuiltinFunction(stepsRejected, lengthRejected, "", « [[AlreadyCalled]], [[Index]], [[Errors]], [[Capability]], [[RemainingElements]] »).
2021-11-14 00:33:16 +00:00
// m. Set onRejected.[[AlreadyCalled]] to false.
// n. Set onRejected.[[Index]] to index.
// o. Set onRejected.[[Errors]] to errors.
// p. Set onRejected.[[Capability]] to resultCapability.
// q. Set onRejected.[[RemainingElements]] to remainingElementsCount.
2022-12-13 20:49:50 +00:00
auto on_rejected = PromiseAnyRejectElementFunction : : create ( realm , index , errors , result_capability , remaining_elements_count ) ;
2023-01-21 10:42:46 -05:00
on_rejected - > define_direct_property ( vm . names . name , PrimitiveString : : create ( vm , String { } ) , Attribute : : Configurable ) ;
2021-08-21 16:43:38 -04:00
2021-11-14 00:33:16 +00:00
// s. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], onRejected »).
2022-10-02 12:11:30 +01:00
return next_promise . invoke ( vm , vm . names . then , result_capability . resolve ( ) , on_rejected ) ;
2021-08-21 16:43:38 -04:00
} ) ;
}
2021-08-21 17:12:24 -04:00
// 27.2.4.5.1 PerformPromiseRace ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiserace
2023-06-23 15:35:19 -04:00
static ThrowCompletionOr < Value > perform_promise_race ( VM & vm , IteratorRecord & iterator_record , Value constructor , PromiseCapability const & result_capability , Value promise_resolve )
2021-08-21 17:12:24 -04:00
{
return perform_promise_common (
2022-08-21 16:09:38 +01:00
vm , iterator_record , constructor , result_capability , promise_resolve ,
2021-10-19 22:53:27 +03:00
[ & ] ( PromiseValueList & ) - > ThrowCompletionOr < Value > {
2021-11-14 00:33:16 +00:00
// ii. Return resultCapability.[[Promise]].
2022-10-02 12:11:30 +01:00
return result_capability . promise ( ) ;
2021-08-21 17:12:24 -04:00
} ,
[ & ] ( PromiseValueList & , RemainingElements & , Value next_promise , size_t ) {
2021-11-14 00:33:16 +00:00
// i. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
2022-10-02 12:11:30 +01:00
return next_promise . invoke ( vm , vm . names . then , result_capability . resolve ( ) , result_capability . reject ( ) ) ;
2021-08-21 17:12:24 -04:00
} ) ;
}
2022-08-16 00:20:49 +01:00
PromiseConstructor : : PromiseConstructor ( Realm & realm )
2023-04-13 00:47:15 +02:00
: NativeFunction ( realm . vm ( ) . names . Promise . as_string ( ) , realm . intrinsics ( ) . function_prototype ( ) )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
}
2023-08-07 08:41:28 +02:00
void PromiseConstructor : : initialize ( Realm & realm )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
auto & vm = this - > vm ( ) ;
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
2021-06-13 00:22:35 +01:00
// 27.2.4.4 Promise.prototype, https://tc39.es/ecma262/#sec-promise.prototype
2022-08-27 00:54:55 +01:00
define_direct_property ( vm . names . prototype , realm . intrinsics ( ) . promise_prototype ( ) , 0 ) ;
2021-06-13 00:22:35 +01:00
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
u8 attr = Attribute : : Writable | Attribute : : Configurable ;
2022-08-22 21:47:35 +01:00
define_native_function ( realm , vm . names . all , all , 1 , attr ) ;
define_native_function ( realm , vm . names . allSettled , all_settled , 1 , attr ) ;
define_native_function ( realm , vm . names . any , any , 1 , attr ) ;
define_native_function ( realm , vm . names . race , race , 1 , attr ) ;
define_native_function ( realm , vm . names . reject , reject , 1 , attr ) ;
define_native_function ( realm , vm . names . resolve , resolve , 1 , attr ) ;
2024-04-09 07:02:15 +01:00
define_native_function ( realm , vm . names . try_ , try_ , 1 , attr ) ;
2023-07-12 15:28:03 -04:00
define_native_function ( realm , vm . names . withResolvers , with_resolvers , 0 , attr ) ;
2022-08-22 21:47:35 +01:00
2023-04-13 01:14:45 +02:00
define_native_accessor ( realm , vm . well_known_symbol_species ( ) , symbol_species_getter , { } , Attribute : : Configurable ) ;
2021-07-08 02:49:53 +03:00
define_direct_property ( vm . names . length , Value ( 1 ) , Attribute : : Configurable ) ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2021-06-13 00:22:35 +01:00
// 27.2.3.1 Promise ( executor ), https://tc39.es/ecma262/#sec-promise-executor
2021-10-20 21:16:30 +01:00
ThrowCompletionOr < Value > PromiseConstructor : : call ( )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
auto & vm = this - > vm ( ) ;
2021-11-14 00:33:16 +00:00
// 1. If NewTarget is undefined, throw a TypeError exception.
2022-08-16 20:33:17 +01:00
return vm . throw_completion < TypeError > ( ErrorType : : ConstructorWithoutNew , vm . names . Promise ) ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2021-06-13 00:22:35 +01:00
// 27.2.3.1 Promise ( executor ), https://tc39.es/ecma262/#sec-promise-executor
2022-12-14 19:18:10 +00:00
ThrowCompletionOr < NonnullGCPtr < Object > > PromiseConstructor : : construct ( FunctionObject & new_target )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
auto & vm = this - > vm ( ) ;
2021-06-20 01:09:39 +01:00
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
auto executor = vm . argument ( 0 ) ;
2021-11-14 00:33:16 +00:00
// 2. If IsCallable(executor) is false, throw a TypeError exception.
2021-10-20 21:16:30 +01:00
if ( ! executor . is_function ( ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < TypeError > ( ErrorType : : PromiseExecutorNotAFunction ) ;
2021-06-20 01:09:39 +01:00
2021-11-14 00:33:16 +00:00
// 3. Let promise be ? OrdinaryCreateFromConstructor(NewTarget, "%Promise.prototype%", « [[PromiseState]], [[PromiseResult]], [[PromiseFulfillReactions]], [[PromiseRejectReactions]], [[PromiseIsHandled]] »).
// 4. Set promise.[[PromiseState]] to pending.
// 5. Set promise.[[PromiseFulfillReactions]] to a new empty List.
// 6. Set promise.[[PromiseRejectReactions]] to a new empty List.
// 7. Set promise.[[PromiseIsHandled]] to false.
2022-12-13 20:49:50 +00:00
auto promise = TRY ( ordinary_create_from_constructor < Promise > ( vm , new_target , & Intrinsics : : promise_prototype ) ) ;
2021-06-20 01:09:39 +01:00
2021-11-14 00:33:16 +00:00
// 8. Let resolvingFunctions be CreateResolvingFunctions(promise).
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
auto [ resolve_function , reject_function ] = promise - > create_resolving_functions ( ) ;
2022-05-02 20:54:39 +02:00
// 9. Let completion be Completion(Call(executor, undefined, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »)).
2023-02-26 16:09:02 -07:00
auto completion = JS : : call ( vm , executor . as_function ( ) , js_undefined ( ) , resolve_function , reject_function ) ;
2021-11-14 00:33:16 +00:00
// 10. If completion is an abrupt completion, then
2022-02-07 15:12:41 +01:00
if ( completion . is_error ( ) ) {
2021-11-14 00:33:16 +00:00
// a. Perform ? Call(resolvingFunctions.[[Reject]], undefined, « completion.[[Value]] »).
2023-02-26 16:09:02 -07:00
TRY ( JS : : call ( vm , * reject_function , js_undefined ( ) , * completion . release_error ( ) . value ( ) ) ) ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2021-11-14 00:33:16 +00:00
// 11. Return promise.
2022-12-14 19:18:10 +00:00
return promise ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2021-06-13 00:22:35 +01:00
// 27.2.4.1 Promise.all ( iterable ), https://tc39.es/ecma262/#sec-promise.all
2021-10-23 03:44:59 +03:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : all )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
2021-11-14 00:33:16 +00:00
// 1. Let C be the this value.
2023-04-13 15:26:41 +02:00
auto constructor = TRY ( vm . this_value ( ) . to_object ( vm ) ) ;
2021-08-21 13:41:32 -04:00
2021-11-14 00:33:16 +00:00
// 2. Let promiseCapability be ? NewPromiseCapability(C).
2022-08-21 16:09:38 +01:00
auto promise_capability = TRY ( new_promise_capability ( vm , constructor ) ) ;
2021-08-21 13:41:32 -04:00
2022-05-02 20:54:39 +02:00
// 3. Let promiseResolve be Completion(GetPromiseResolve(C)).
2021-11-14 00:33:16 +00:00
// 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
2022-08-21 16:09:38 +01:00
auto promise_resolve = TRY_OR_REJECT ( vm , promise_capability , get_promise_resolve ( vm , constructor ) ) ;
2021-11-14 00:33:16 +00:00
2023-07-18 14:52:21 -04:00
// 5. Let iteratorRecord be Completion(GetIterator(iterable, sync)).
2021-11-14 00:33:16 +00:00
// 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
2023-07-18 14:52:21 -04:00
auto iterator_record = TRY_OR_REJECT ( vm , promise_capability , get_iterator ( vm , vm . argument ( 0 ) , IteratorHint : : Sync ) ) ;
2021-08-21 13:41:32 -04:00
2022-05-02 20:54:39 +02:00
// 7. Let result be Completion(PerformPromiseAll(iteratorRecord, C, promiseCapability, promiseResolve)).
2022-08-21 16:09:38 +01:00
auto result = perform_promise_all ( vm , iterator_record , constructor , promise_capability , promise_resolve ) ;
2021-11-14 00:33:16 +00:00
// 8. If result is an abrupt completion, then
2021-10-20 22:55:17 -04:00
if ( result . is_error ( ) ) {
2022-05-02 20:54:39 +02:00
// a. If iteratorRecord.[[Done]] is false, set result to Completion(IteratorClose(iteratorRecord, result)).
2023-12-07 10:44:41 +01:00
if ( ! iterator_record - > done )
2022-08-21 15:56:27 +01:00
result = iterator_close ( vm , iterator_record , result . release_error ( ) ) ;
2021-08-21 13:41:32 -04:00
2021-11-14 00:33:16 +00:00
// b. IfAbruptRejectPromise(result, promiseCapability).
2022-08-21 16:09:38 +01:00
TRY_OR_REJECT ( vm , promise_capability , result ) ;
2021-08-21 13:41:32 -04:00
}
2022-05-02 20:54:39 +02:00
// 9. Return ? result.
return result ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2021-06-13 00:22:35 +01:00
// 27.2.4.2 Promise.allSettled ( iterable ), https://tc39.es/ecma262/#sec-promise.allsettled
2021-10-23 03:44:59 +03:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : all_settled )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
2021-11-14 00:33:16 +00:00
// 1. Let C be the this value.
2023-04-13 15:26:41 +02:00
auto constructor = TRY ( vm . this_value ( ) . to_object ( vm ) ) ;
2021-08-21 17:00:48 -04:00
2021-11-14 00:33:16 +00:00
// 2. Let promiseCapability be ? NewPromiseCapability(C).
2022-08-21 16:09:38 +01:00
auto promise_capability = TRY ( new_promise_capability ( vm , constructor ) ) ;
2021-08-21 17:00:48 -04:00
2022-05-02 20:54:39 +02:00
// 3. Let promiseResolve be Completion(GetPromiseResolve(C)).
2021-11-14 00:33:16 +00:00
// 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
2022-08-21 16:09:38 +01:00
auto promise_resolve = TRY_OR_REJECT ( vm , promise_capability , get_promise_resolve ( vm , constructor ) ) ;
2021-11-14 00:33:16 +00:00
2023-07-18 14:52:21 -04:00
// 5. Let iteratorRecord be Completion(GetIterator(iterable, sync)).
2021-11-14 00:33:16 +00:00
// 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
2023-07-18 14:52:21 -04:00
auto iterator_record = TRY_OR_REJECT ( vm , promise_capability , get_iterator ( vm , vm . argument ( 0 ) , IteratorHint : : Sync ) ) ;
2021-08-21 17:00:48 -04:00
2022-05-02 20:54:39 +02:00
// 7. Let result be Completion(PerformPromiseAllSettled(iteratorRecord, C, promiseCapability, promiseResolve)).
2022-08-21 16:09:38 +01:00
auto result = perform_promise_all_settled ( vm , iterator_record , constructor , promise_capability , promise_resolve ) ;
2021-11-14 00:33:16 +00:00
// 8. If result is an abrupt completion, then
2021-10-20 22:55:17 -04:00
if ( result . is_error ( ) ) {
2022-05-02 20:54:39 +02:00
// a. If iteratorRecord.[[Done]] is false, set result to Completion(IteratorClose(iteratorRecord, result)).
2023-12-07 10:44:41 +01:00
if ( ! iterator_record - > done )
2022-08-21 15:56:27 +01:00
result = iterator_close ( vm , iterator_record , result . release_error ( ) ) ;
2021-08-21 17:00:48 -04:00
2021-11-14 00:33:16 +00:00
// b. IfAbruptRejectPromise(result, promiseCapability).
2022-08-21 16:09:38 +01:00
TRY_OR_REJECT ( vm , promise_capability , result ) ;
2021-08-21 17:00:48 -04:00
}
2022-05-02 20:54:39 +02:00
// 9. Return ? result.
return result ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2021-06-13 00:22:35 +01:00
// 27.2.4.3 Promise.any ( iterable ), https://tc39.es/ecma262/#sec-promise.any
2021-10-23 03:44:59 +03:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : any )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
2021-11-14 00:33:16 +00:00
// 1. Let C be the this value.
2023-04-13 15:26:41 +02:00
auto constructor = TRY ( vm . this_value ( ) . to_object ( vm ) ) ;
2021-08-21 16:43:38 -04:00
2021-11-14 00:33:16 +00:00
// 2. Let promiseCapability be ? NewPromiseCapability(C).
2022-08-21 16:09:38 +01:00
auto promise_capability = TRY ( new_promise_capability ( vm , constructor ) ) ;
2021-08-21 16:43:38 -04:00
2022-05-02 20:54:39 +02:00
// 3. Let promiseResolve be Completion(GetPromiseResolve(C)).
2021-11-14 00:33:16 +00:00
// 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
2022-08-21 16:09:38 +01:00
auto promise_resolve = TRY_OR_REJECT ( vm , promise_capability , get_promise_resolve ( vm , constructor ) ) ;
2021-11-14 00:33:16 +00:00
2023-07-18 14:52:21 -04:00
// 5. Let iteratorRecord be Completion(GetIterator(iterable, sync)).
2021-11-14 00:33:16 +00:00
// 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
2023-07-18 14:52:21 -04:00
auto iterator_record = TRY_OR_REJECT ( vm , promise_capability , get_iterator ( vm , vm . argument ( 0 ) , IteratorHint : : Sync ) ) ;
2021-08-21 16:43:38 -04:00
2022-05-02 20:54:39 +02:00
// 7. Let result be Completion(PerformPromiseAny(iteratorRecord, C, promiseCapability, promiseResolve)).
2022-08-21 16:09:38 +01:00
auto result = perform_promise_any ( vm , iterator_record , constructor , promise_capability , promise_resolve ) ;
2021-11-14 00:33:16 +00:00
// 8. If result is an abrupt completion, then
2021-10-20 22:55:17 -04:00
if ( result . is_error ( ) ) {
2022-05-02 20:54:39 +02:00
// a. If iteratorRecord.[[Done]] is false, set result to Completion(IteratorClose(iteratorRecord, result)).
2023-12-07 10:44:41 +01:00
if ( ! iterator_record - > done )
2022-08-21 15:56:27 +01:00
result = iterator_close ( vm , iterator_record , result . release_error ( ) ) ;
2021-08-21 16:43:38 -04:00
2021-11-14 00:33:16 +00:00
// b. IfAbruptRejectPromise(result, promiseCapability).
2022-08-21 16:09:38 +01:00
TRY_OR_REJECT ( vm , promise_capability , result ) ;
2021-08-21 16:43:38 -04:00
}
2022-05-02 20:54:39 +02:00
// 9. Return ? result.
return result ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2021-06-13 00:22:35 +01:00
// 27.2.4.5 Promise.race ( iterable ), https://tc39.es/ecma262/#sec-promise.race
2021-10-23 03:44:59 +03:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : race )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
2021-11-14 00:33:16 +00:00
// 1. Let C be the this value.
2023-04-13 15:26:41 +02:00
auto constructor = TRY ( vm . this_value ( ) . to_object ( vm ) ) ;
2021-08-21 17:12:24 -04:00
2021-11-14 00:33:16 +00:00
// 2. Let promiseCapability be ? NewPromiseCapability(C).
2022-08-21 16:09:38 +01:00
auto promise_capability = TRY ( new_promise_capability ( vm , constructor ) ) ;
2021-08-21 17:12:24 -04:00
2022-05-02 20:54:39 +02:00
// 3. Let promiseResolve be Completion(GetPromiseResolve(C)).
2021-11-14 00:33:16 +00:00
// 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
2022-08-21 16:09:38 +01:00
auto promise_resolve = TRY_OR_REJECT ( vm , promise_capability , get_promise_resolve ( vm , constructor ) ) ;
2021-11-14 00:33:16 +00:00
2023-07-18 14:52:21 -04:00
// 5. Let iteratorRecord be Completion(GetIterator(iterable, sync)).
2021-11-14 00:33:16 +00:00
// 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
2023-07-18 14:52:21 -04:00
auto iterator_record = TRY_OR_REJECT ( vm , promise_capability , get_iterator ( vm , vm . argument ( 0 ) , IteratorHint : : Sync ) ) ;
2021-08-21 17:12:24 -04:00
2022-05-02 20:54:39 +02:00
// 7. Let result be Completion(PerformPromiseRace(iteratorRecord, C, promiseCapability, promiseResolve)).
2022-08-21 16:09:38 +01:00
auto result = perform_promise_race ( vm , iterator_record , constructor , promise_capability , promise_resolve ) ;
2021-11-14 00:33:16 +00:00
// 8. If result is an abrupt completion, then
2021-10-20 22:55:17 -04:00
if ( result . is_error ( ) ) {
2022-05-02 20:54:39 +02:00
// a. If iteratorRecord.[[Done]] is false, set result to Completion(IteratorClose(iteratorRecord, result)).
2023-12-07 10:44:41 +01:00
if ( ! iterator_record - > done )
2022-08-21 15:56:27 +01:00
result = iterator_close ( vm , iterator_record , result . release_error ( ) ) ;
2021-08-21 17:12:24 -04:00
2021-11-14 00:33:16 +00:00
// b. IfAbruptRejectPromise(result, promiseCapability).
2022-08-21 16:09:38 +01:00
TRY_OR_REJECT ( vm , promise_capability , result ) ;
2021-08-21 17:12:24 -04:00
}
2022-05-02 20:54:39 +02:00
// 9. Return ? result.
return result ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2021-06-13 00:22:35 +01:00
// 27.2.4.6 Promise.reject ( r ), https://tc39.es/ecma262/#sec-promise.reject
2021-10-23 03:44:59 +03:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : reject )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
2021-11-14 00:33:16 +00:00
auto reason = vm . argument ( 0 ) ;
// 1. Let C be the this value.
2023-04-13 15:26:41 +02:00
auto constructor = TRY ( vm . this_value ( ) . to_object ( vm ) ) ;
2021-11-14 00:33:16 +00:00
// 2. Let promiseCapability be ? NewPromiseCapability(C).
2022-08-21 16:09:38 +01:00
auto promise_capability = TRY ( new_promise_capability ( vm , constructor ) ) ;
2021-11-14 00:33:16 +00:00
// 3. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
2022-10-02 12:11:30 +01:00
[[maybe_unused]] auto result = TRY ( JS : : call ( vm , * promise_capability - > reject ( ) , js_undefined ( ) , reason ) ) ;
2021-11-14 00:33:16 +00:00
// 4. Return promiseCapability.[[Promise]].
2022-10-02 12:11:30 +01:00
return promise_capability - > promise ( ) ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2021-06-13 00:22:35 +01:00
// 27.2.4.7 Promise.resolve ( x ), https://tc39.es/ecma262/#sec-promise.resolve
2021-10-23 03:44:59 +03:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : resolve )
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
{
auto value = vm . argument ( 0 ) ;
2021-11-14 00:33:16 +00:00
// 1. Let C be the this value.
2022-08-20 09:48:43 +01:00
auto constructor = vm . this_value ( ) ;
2021-11-14 00:58:15 +00:00
2021-11-14 00:33:16 +00:00
// 2. If Type(C) is not Object, throw a TypeError exception.
2021-11-14 00:58:15 +00:00
if ( ! constructor . is_object ( ) )
2023-08-09 08:49:02 +02:00
return vm . throw_completion < TypeError > ( ErrorType : : NotAnObject , constructor . to_string_without_side_effects ( ) ) ;
2021-11-14 00:33:16 +00:00
// 3. Return ? PromiseResolve(C, x).
2022-08-21 16:09:38 +01:00
return TRY ( promise_resolve ( vm , constructor . as_object ( ) , value ) ) ;
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}
2024-10-23 13:36:02 -04:00
// 27.2.4.8 Promise.try ( callback, ...args ), https://tc39.es/ecma262/#sec-promise.try
2024-04-09 07:02:15 +01:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : try_ )
{
2024-10-23 13:36:02 -04:00
auto callback = vm . argument ( 0 ) ;
2024-04-09 07:02:15 +01:00
Span < Value > args ;
if ( vm . argument_count ( ) > 1 ) {
args = vm . running_execution_context ( ) . arguments . span ( ) . slice ( 1 , vm . argument_count ( ) - 1 ) ;
}
// 1. Let C be the this value.
auto constructor = vm . this_value ( ) ;
// 2. If C is not an Object, throw a TypeError exception.
if ( ! constructor . is_object ( ) )
return vm . throw_completion < TypeError > ( ErrorType : : NotAnObject , constructor . to_string_without_side_effects ( ) ) ;
// 3. Let promiseCapability be ? NewPromiseCapability(C).
auto promise_capability = TRY ( new_promise_capability ( vm , constructor ) ) ;
2024-10-23 13:36:02 -04:00
// 4. Let status be Completion(Call(callback, undefined, args)).
auto status = JS : : call ( vm , callback , js_undefined ( ) , args ) ;
2024-04-09 07:02:15 +01:00
// 5. If status is an abrupt completion, then
if ( status . is_throw_completion ( ) ) {
// a. Perform ? Call(promiseCapability.[[Reject]], undefined, « status.[[Value]] »).
TRY ( JS : : call ( vm , * promise_capability - > reject ( ) , js_undefined ( ) , * status . throw_completion ( ) . value ( ) ) ) ;
}
// 6. Else,
else {
// a. Perform ? Call(promiseCapability.[[Resolve]], undefined, « status.[[Value]] »).
TRY ( JS : : call ( vm , * promise_capability - > resolve ( ) , js_undefined ( ) , status . value ( ) ) ) ;
}
// 7. Return promiseCapability.[[Promise]].
return promise_capability - > promise ( ) ;
}
2024-10-23 13:36:02 -04:00
// 27.2.4.9 Promise.withResolvers ( ), https://tc39.es/ecma262/#sec-promise.withResolvers
2023-07-12 15:28:03 -04:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : with_resolvers )
{
auto & realm = * vm . current_realm ( ) ;
// 1. Let C be the this value.
auto constructor = vm . this_value ( ) ;
// 2. Let promiseCapability be ? NewPromiseCapability(C).
auto promise_capability = TRY ( new_promise_capability ( vm , constructor ) ) ;
// 3. Let obj be OrdinaryObjectCreate(%Object.prototype%).
auto object = Object : : create ( realm , realm . intrinsics ( ) . object_prototype ( ) ) ;
// 4. Perform ! CreateDataPropertyOrThrow(obj, "promise", promiseCapability.[[Promise]]).
MUST ( object - > create_data_property_or_throw ( vm . names . promise , promise_capability - > promise ( ) ) ) ;
// 5. Perform ! CreateDataPropertyOrThrow(obj, "resolve", promiseCapability.[[Resolve]]).
MUST ( object - > create_data_property_or_throw ( vm . names . resolve , promise_capability - > resolve ( ) ) ) ;
// 6. Perform ! CreateDataPropertyOrThrow(obj, "reject", promiseCapability.[[Reject]]).
MUST ( object - > create_data_property_or_throw ( vm . names . reject , promise_capability - > reject ( ) ) ) ;
// 7. Return obj.
return object ;
}
2024-10-23 13:36:02 -04:00
// 27.2.4.10 get Promise [ @@species ], https://tc39.es/ecma262/#sec-get-promise-@@species
2023-12-26 08:58:15 -05:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : symbol_species_getter )
{
// 1. Return the this value.
return vm . this_value ( ) ;
}
LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)
The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.
Implemented functions are:
- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()
For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].
Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.
This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.
I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.
[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-01 22:13:29 +02:00
}