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
/*
2022-01-09 19:12:24 +01:00
* Copyright ( c ) 2021 - 2022 , 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>
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/Interpreter.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>
2021-08-21 13:41:32 -04:00
# include <LibJS/Runtime/IteratorOperations.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 {
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 ( ) )
2022-08-16 20:33:17 +01: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
2022-10-02 12:11:30 +01:00
static ThrowCompletionOr < Value > perform_promise_common ( VM & vm , Iterator & 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.
2022-08-16 00:20:50 +01:00
auto * values = vm . heap ( ) . allocate_without_realm < PromiseValueList > ( ) ;
2021-11-14 00:33:16 +00:00
// 2. Let remainingElementsCount be the Record { [[Value]]: 1 }.
2022-08-16 00:20:50 +01:00
auto * remaining_elements_count = vm . heap ( ) . allocate_without_realm < 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 ) {
2022-05-02 20:54:39 +02:00
// a. Let next be Completion(IteratorStep(iteratorRecord)).
2022-08-21 15:56:27 +01:00
auto next_or_error = iterator_step ( vm , iterator_record ) ;
2021-11-14 00:33:16 +00:00
// b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
// c. ReturnIfAbrupt(next).
2021-10-20 08:56:01 -04:00
if ( next_or_error . is_throw_completion ( ) ) {
2022-01-09 19:12:24 +01:00
iterator_record . done = true ;
2021-10-20 22:55:17 -04:00
return next_or_error . release_error ( ) ;
2021-08-21 13:41:32 -04:00
}
2021-10-20 08:56:01 -04:00
auto * next = next_or_error . release_value ( ) ;
2021-08-21 13:41:32 -04:00
2021-11-14 00:33:16 +00:00
// d. If next is false, then
2021-08-21 13:41:32 -04:00
if ( ! next ) {
2021-11-14 00:33:16 +00:00
// i. Set iteratorRecord.[[Done]] to true.
2022-01-09 19:12:24 +01:00
iterator_record . done = true ;
2021-08-21 13:41:32 -04:00
2021-11-14 00:33:16 +00:00
// ii. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
// iii. If remainingElementsCount.[[Value]] is 0, then
if ( - - remaining_elements_count - > value = = 0 ) {
// 1-2/3. 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
}
// iv. Return resultCapability.[[Promise]].
2022-10-02 12:11:30 +01:00
return result_capability . promise ( ) ;
2021-08-21 13:41:32 -04:00
}
2022-05-02 20:54:39 +02:00
// e. Let nextValue be Completion(IteratorValue(next)).
2022-08-21 15:56:27 +01:00
auto next_value_or_error = iterator_value ( vm , * next ) ;
2021-11-14 00:33:16 +00:00
// f. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
// g. ReturnIfAbrupt(nextValue).
2021-10-20 09:05:52 -04:00
if ( next_value_or_error . is_throw_completion ( ) ) {
2022-01-09 19:12:24 +01:00
iterator_record . done = true ;
2021-10-20 22:55:17 -04:00
return next_value_or_error . release_error ( ) ;
2021-08-21 13:41:32 -04:00
}
2021-10-20 09:05:52 -04:00
auto next_value = next_value_or_error . release_value ( ) ;
2021-08-21 13:41:32 -04:00
2021-11-14 00:33:16 +00:00
// h. 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
2021-11-14 00:33:16 +00:00
// i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
2022-08-21 19:24:32 +01:00
auto next_promise = TRY ( call ( vm , promise_resolve . as_function ( ) , constructor , next_value ) ) ;
2021-08-21 13:41:32 -04:00
2021-11-14 00:33:16 +00:00
// j-q. are handled in `invoke_element_function`
// r. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] + 1.
2021-08-21 13:41:32 -04:00
+ + remaining_elements_count - > value ;
2021-11-14 00:33:16 +00:00
// s. 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
// t. 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
2022-10-02 12:11:30 +01:00
static ThrowCompletionOr < Value > perform_promise_all ( VM & vm , Iterator & 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-08-16 00:20:49 +01:00
auto * on_fulfilled = PromiseAllResolveElementFunction : : create ( realm , index , values , result_capability , remaining_elements_count ) ;
2022-12-06 22:17:27 +00:00
on_fulfilled - > define_direct_property ( vm . names . name , PrimitiveString : : create ( vm , DeprecatedString : : empty ( ) ) , 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
2022-10-02 12:11:30 +01:00
static ThrowCompletionOr < Value > perform_promise_all_settled ( VM & vm , Iterator & 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-08-16 00:20:49 +01:00
auto * on_fulfilled = PromiseAllSettledResolveElementFunction : : create ( realm , index , values , result_capability , remaining_elements_count ) ;
2022-12-06 22:17:27 +00:00
on_fulfilled - > define_direct_property ( vm . names . name , PrimitiveString : : create ( vm , DeprecatedString : : empty ( ) ) , 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-08-16 00:20:49 +01:00
auto * on_rejected = PromiseAllSettledRejectElementFunction : : create ( realm , index , values , result_capability , remaining_elements_count ) ;
2022-12-06 22:17:27 +00:00
on_rejected - > define_direct_property ( vm . names . name , PrimitiveString : : create ( vm , DeprecatedString : : empty ( ) ) , 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
2022-10-02 12:11:30 +01:00
static ThrowCompletionOr < Value > perform_promise_any ( VM & vm , Iterator & iterator_record , Value constructor , PromiseCapability const & 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-08-16 00:20:49 +01:00
auto * on_rejected = PromiseAnyRejectElementFunction : : create ( realm , index , errors , result_capability , remaining_elements_count ) ;
2022-12-06 22:17:27 +00:00
on_rejected - > define_direct_property ( vm . names . name , PrimitiveString : : create ( vm , DeprecatedString : : empty ( ) ) , 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
2022-10-02 12:11:30 +01:00
static ThrowCompletionOr < Value > perform_promise_race ( VM & vm , Iterator & 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 )
2022-09-14 19:10:27 -04: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
{
}
2022-08-16 00:20:49 +01: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 ( ) ;
2022-08-16 00:20:49 +01:00
NativeFunction : : 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 ) ;
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
2021-10-20 21:16:30 +01:00
ThrowCompletionOr < 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-08-27 00:54:55 +01: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]] »)).
2022-08-21 19:24:32 +01: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]] »).
2022-08-21 19:24:32 +01: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.
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
return promise ;
}
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.
2022-08-21 14:00:56 +01: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
2022-05-02 20:54:39 +02:00
// 5. Let iteratorRecord be Completion(GetIterator(iterable)).
2021-11-14 00:33:16 +00:00
// 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
2022-08-21 16:09:38 +01:00
auto iterator_record = TRY_OR_REJECT ( vm , promise_capability , get_iterator ( vm , vm . argument ( 0 ) ) ) ;
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)).
2022-01-09 19:12:24 +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.
2022-08-21 14:00:56 +01: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
2022-05-02 20:54:39 +02:00
// 5. Let iteratorRecord be Completion(GetIterator(iterable)).
2021-11-14 00:33:16 +00:00
// 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
2022-08-21 16:09:38 +01:00
auto iterator_record = TRY_OR_REJECT ( vm , promise_capability , get_iterator ( vm , vm . argument ( 0 ) ) ) ;
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)).
2022-01-09 19:12:24 +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.
2022-08-21 14:00:56 +01: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
2022-05-02 20:54:39 +02:00
// 5. Let iteratorRecord be Completion(GetIterator(iterable)).
2021-11-14 00:33:16 +00:00
// 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
2022-08-21 16:09:38 +01:00
auto iterator_record = TRY_OR_REJECT ( vm , promise_capability , get_iterator ( vm , vm . argument ( 0 ) ) ) ;
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)).
2022-01-09 19:12:24 +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.
2022-08-21 14:00:56 +01: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
2022-05-02 20:54:39 +02:00
// 5. Let iteratorRecord be Completion(GetIterator(iterable)).
2021-11-14 00:33:16 +00:00
// 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
2022-08-21 16:09:38 +01:00
auto iterator_record = TRY_OR_REJECT ( vm , promise_capability , get_iterator ( vm , vm . argument ( 0 ) ) ) ;
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)).
2022-01-09 19:12:24 +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.
2022-08-21 14:00:56 +01: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 ( ) )
2022-08-16 20:33:17 +01: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
}
2021-06-13 00:22:35 +01:00
// 27.2.4.8 get Promise [ @@species ], https://tc39.es/ecma262/#sec-get-promise-@@species
2021-10-23 03:44:59 +03:00
JS_DEFINE_NATIVE_FUNCTION ( PromiseConstructor : : symbol_species_getter )
2021-06-07 19:31:32 +03:00
{
2021-11-14 00:33:16 +00:00
// 1. Return the this value.
2022-08-20 09:48:43 +01:00
return vm . this_value ( ) ;
2021-06-07 19:31:32 +03: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
}