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 22:51:19 +02:00
|
|
|
* Copyright (c) 2021, 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>
|
|
|
|
#include <LibJS/Runtime/PromiseConstructor.h>
|
|
|
|
#include <LibJS/Runtime/PromiseReaction.h>
|
2021-08-21 15:23:12 -04:00
|
|
|
#include <LibJS/Runtime/PromiseResolvingElementFunctions.h>
|
2021-08-21 13:41:32 -04:00
|
|
|
#include <LibJS/Runtime/TemporaryClearException.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
|
2021-10-20 22:10:08 -04:00
|
|
|
static ThrowCompletionOr<Value> get_promise_resolve(GlobalObject& global_object, Value constructor)
|
2021-08-21 13:41:32 -04:00
|
|
|
{
|
|
|
|
VERIFY(constructor.is_constructor());
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
2021-10-20 22:10:08 -04:00
|
|
|
auto promise_resolve = TRY(constructor.get(global_object, vm.names.resolve));
|
|
|
|
if (!promise_resolve.is_function())
|
|
|
|
return vm.throw_completion<TypeError>(global_object, ErrorType::NotAFunction, promise_resolve.to_string_without_side_effects());
|
2021-08-21 13:41:32 -04:00
|
|
|
|
|
|
|
return promise_resolve;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise
|
2021-10-20 22:35:43 -04:00
|
|
|
#define TRY_OR_REJECT(vm, capability, expression) \
|
|
|
|
({ \
|
|
|
|
auto _temporary_result = (expression); \
|
|
|
|
if (_temporary_result.is_error()) { \
|
|
|
|
vm.clear_exception(); \
|
|
|
|
vm.stop_unwind(); \
|
|
|
|
\
|
|
|
|
(void)vm.call(*capability.reject, js_undefined(), _temporary_result.release_error().value()); \
|
|
|
|
return capability.promise; \
|
|
|
|
} \
|
|
|
|
_temporary_result.release_value(); \
|
|
|
|
})
|
2021-08-21 13:41:32 -04:00
|
|
|
|
|
|
|
static bool iterator_record_is_complete(GlobalObject& global_object, Object& iterator_record)
|
|
|
|
{
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
|
|
|
// FIXME: Create a native iterator structure with the [[Done]] internal slot. For now, temporarily clear
|
|
|
|
// the exception so we can access the "done" property on the iterator object.
|
|
|
|
TemporaryClearException clear_exception(vm);
|
2021-10-20 09:00:37 -04:00
|
|
|
return MUST(iterator_complete(global_object, iterator_record));
|
2021-08-21 13:41:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void set_iterator_record_complete(GlobalObject& global_object, Object& iterator_record)
|
|
|
|
{
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
|
|
|
// FIXME: Create a native iterator structure with the [[Done]] internal slot. For now, temporarily clear
|
|
|
|
// the exception so we can access the "done" property on the iterator object.
|
|
|
|
TemporaryClearException clear_exception(vm);
|
2021-10-03 00:32:43 +01:00
|
|
|
MUST(iterator_record.set(vm.names.done, Value(true), Object::ShouldThrowExceptions::No));
|
2021-08-21 13:41:32 -04:00
|
|
|
}
|
|
|
|
|
2021-10-19 22:53:27 +03:00
|
|
|
using EndOfElementsCallback = Function<ThrowCompletionOr<Value>(PromiseValueList&)>;
|
2021-08-21 16:31:55 -04:00
|
|
|
using InvokeElementFunctionCallback = Function<void(PromiseValueList&, RemainingElements&, Value, size_t)>;
|
|
|
|
|
|
|
|
static Value perform_promise_common(GlobalObject& global_object, Object& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve, EndOfElementsCallback end_of_list, InvokeElementFunctionCallback invoke_element_function)
|
2021-08-21 13:41:32 -04:00
|
|
|
{
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
|
|
|
VERIFY(constructor.is_constructor());
|
|
|
|
VERIFY(promise_resolve.is_function());
|
|
|
|
|
|
|
|
auto* values = vm.heap().allocate_without_global_object<PromiseValueList>();
|
|
|
|
auto* remaining_elements_count = vm.heap().allocate_without_global_object<RemainingElements>(1);
|
|
|
|
size_t index = 0;
|
|
|
|
|
|
|
|
while (true) {
|
2021-10-20 08:56:01 -04:00
|
|
|
auto next_or_error = iterator_step(global_object, iterator_record);
|
|
|
|
if (next_or_error.is_throw_completion()) {
|
2021-08-21 13:41:32 -04:00
|
|
|
set_iterator_record_complete(global_object, iterator_record);
|
|
|
|
return {};
|
|
|
|
}
|
2021-10-20 08:56:01 -04:00
|
|
|
auto* next = next_or_error.release_value();
|
2021-08-21 13:41:32 -04:00
|
|
|
|
|
|
|
if (!next) {
|
|
|
|
set_iterator_record_complete(global_object, iterator_record);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
2021-08-21 16:31:55 -04:00
|
|
|
if (--remaining_elements_count->value == 0)
|
2021-10-19 22:53:27 +03:00
|
|
|
return TRY_OR_DISCARD(end_of_list(*values));
|
2021-08-21 13:41:32 -04:00
|
|
|
return result_capability.promise;
|
|
|
|
}
|
|
|
|
|
2021-10-20 09:05:52 -04:00
|
|
|
auto next_value_or_error = iterator_value(global_object, *next);
|
|
|
|
if (next_value_or_error.is_throw_completion()) {
|
2021-08-21 13:41:32 -04:00
|
|
|
set_iterator_record_complete(global_object, iterator_record);
|
|
|
|
return {};
|
|
|
|
}
|
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-09-11 22:16:30 +02:00
|
|
|
values->values().append(js_undefined());
|
2021-08-21 13:41:32 -04:00
|
|
|
|
2021-09-23 20:56:28 +03:00
|
|
|
auto next_promise = TRY_OR_DISCARD(vm.call(promise_resolve.as_function(), constructor, next_value));
|
2021-08-21 13:41:32 -04:00
|
|
|
|
|
|
|
++remaining_elements_count->value;
|
|
|
|
|
2021-08-21 16:31:55 -04:00
|
|
|
invoke_element_function(*values, *remaining_elements_count, next_promise, index);
|
2021-08-21 13:41:32 -04:00
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
++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
|
|
|
|
static Value perform_promise_all(GlobalObject& global_object, Object& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve)
|
|
|
|
{
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
|
|
|
return perform_promise_common(
|
|
|
|
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
2021-10-19 22:53:27 +03:00
|
|
|
[&](PromiseValueList& values) -> ThrowCompletionOr<Value> {
|
2021-09-11 22:16:30 +02:00
|
|
|
auto values_array = Array::create_from(global_object, values.values());
|
2021-08-21 16:31:55 -04:00
|
|
|
|
2021-10-19 22:53:27 +03:00
|
|
|
TRY(vm.call(*result_capability.resolve, js_undefined(), values_array));
|
2021-08-21 16:31:55 -04:00
|
|
|
|
2021-10-19 22:53:27 +03:00
|
|
|
return Value(result_capability.promise);
|
2021-08-21 16:31:55 -04:00
|
|
|
},
|
|
|
|
[&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
|
|
|
|
auto* on_fulfilled = PromiseAllResolveElementFunction::create(global_object, index, values, result_capability, remaining_elements_count);
|
|
|
|
on_fulfilled->define_direct_property(vm.names.name, js_string(vm, String::empty()), Attribute::Configurable);
|
|
|
|
|
|
|
|
(void)next_promise.invoke(global_object, vm.names.then, on_fulfilled, result_capability.reject);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-08-21 17:00:48 -04:00
|
|
|
// 27.2.4.2.1 PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseallsettled
|
|
|
|
static Value perform_promise_all_settled(GlobalObject& global_object, Object& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve)
|
|
|
|
{
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
|
|
|
return perform_promise_common(
|
|
|
|
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
2021-10-19 22:53:27 +03:00
|
|
|
[&](PromiseValueList& values) -> ThrowCompletionOr<Value> {
|
2021-09-11 22:16:30 +02:00
|
|
|
auto values_array = Array::create_from(global_object, values.values());
|
2021-08-21 17:00:48 -04:00
|
|
|
|
2021-10-19 22:53:27 +03:00
|
|
|
TRY(vm.call(*result_capability.resolve, js_undefined(), values_array));
|
2021-08-21 17:00:48 -04:00
|
|
|
|
2021-10-19 22:53:27 +03:00
|
|
|
return Value(result_capability.promise);
|
2021-08-21 17:00:48 -04:00
|
|
|
},
|
|
|
|
[&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
|
|
|
|
auto* on_fulfilled = PromiseAllSettledResolveElementFunction::create(global_object, index, values, result_capability, remaining_elements_count);
|
|
|
|
on_fulfilled->define_direct_property(vm.names.name, js_string(vm, String::empty()), Attribute::Configurable);
|
|
|
|
|
|
|
|
auto* on_rejected = PromiseAllSettledRejectElementFunction::create(global_object, index, values, result_capability, remaining_elements_count);
|
|
|
|
on_rejected->define_direct_property(vm.names.name, js_string(vm, String::empty()), Attribute::Configurable);
|
|
|
|
|
|
|
|
(void)next_promise.invoke(global_object, vm.names.then, on_fulfilled, on_rejected);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-08-21 16:43:38 -04:00
|
|
|
// 27.2.4.3.1 PerformPromiseAny ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseany
|
|
|
|
static Value perform_promise_any(GlobalObject& global_object, Object& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve)
|
|
|
|
{
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
|
|
|
return perform_promise_common(
|
|
|
|
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
2021-10-19 22:53:27 +03:00
|
|
|
[&](PromiseValueList& errors) -> ThrowCompletionOr<Value> {
|
2021-09-11 22:16:30 +02:00
|
|
|
auto errors_array = Array::create_from(global_object, errors.values());
|
2021-08-21 16:43:38 -04:00
|
|
|
|
|
|
|
auto* error = AggregateError::create(global_object);
|
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
|
|
|
|
|
|
|
vm.throw_exception(global_object, 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) {
|
|
|
|
auto* on_rejected = PromiseAnyRejectElementFunction::create(global_object, index, errors, result_capability, remaining_elements_count);
|
|
|
|
on_rejected->define_direct_property(vm.names.name, js_string(vm, String::empty()), Attribute::Configurable);
|
|
|
|
|
|
|
|
(void)next_promise.invoke(global_object, vm.names.then, result_capability.resolve, on_rejected);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-08-21 17:12:24 -04:00
|
|
|
// 27.2.4.5.1 PerformPromiseRace ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiserace
|
|
|
|
static Value perform_promise_race(GlobalObject& global_object, Object& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve)
|
|
|
|
{
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
|
|
|
return perform_promise_common(
|
|
|
|
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
2021-10-19 22:53:27 +03:00
|
|
|
[&](PromiseValueList&) -> ThrowCompletionOr<Value> {
|
|
|
|
return Value(result_capability.promise);
|
2021-08-21 17:12:24 -04:00
|
|
|
},
|
|
|
|
[&](PromiseValueList&, RemainingElements&, Value next_promise, size_t) {
|
|
|
|
(void)next_promise.invoke(global_object, vm.names.then, result_capability.resolve, result_capability.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
|
|
|
PromiseConstructor::PromiseConstructor(GlobalObject& global_object)
|
2021-06-28 03:45:49 +03:00
|
|
|
: NativeFunction(vm().names.Promise.as_string(), *global_object.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
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void PromiseConstructor::initialize(GlobalObject& global_object)
|
|
|
|
{
|
|
|
|
auto& vm = this->vm();
|
|
|
|
NativeFunction::initialize(global_object);
|
|
|
|
|
2021-06-13 00:22:35 +01:00
|
|
|
// 27.2.4.4 Promise.prototype, https://tc39.es/ecma262/#sec-promise.prototype
|
2021-07-06 02:15:08 +03:00
|
|
|
define_direct_property(vm.names.prototype, global_object.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;
|
2021-10-20 01:40:40 +03:00
|
|
|
define_old_native_function(vm.names.all, all, 1, attr);
|
|
|
|
define_old_native_function(vm.names.allSettled, all_settled, 1, attr);
|
|
|
|
define_old_native_function(vm.names.any, any, 1, attr);
|
|
|
|
define_old_native_function(vm.names.race, race, 1, attr);
|
|
|
|
define_old_native_function(vm.names.reject, reject, 1, attr);
|
|
|
|
define_old_native_function(vm.names.resolve, resolve, 1, attr);
|
|
|
|
|
|
|
|
define_old_native_accessor(*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-10-20 21:16:30 +01:00
|
|
|
return vm.throw_completion<TypeError>(global_object(), 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
|
|
|
auto& global_object = this->global_object();
|
|
|
|
|
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-10-20 21:16:30 +01:00
|
|
|
if (!executor.is_function())
|
|
|
|
return vm.throw_completion<TypeError>(global_object, ErrorType::PromiseExecutorNotAFunction);
|
2021-06-20 01:09:39 +01:00
|
|
|
|
2021-10-20 21:16:30 +01:00
|
|
|
auto* promise = TRY(ordinary_create_from_constructor<Promise>(global_object, new_target, &GlobalObject::promise_prototype));
|
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 [resolve_function, reject_function] = promise->create_resolving_functions();
|
|
|
|
|
2021-07-05 13:10:04 +01:00
|
|
|
(void)vm.call(executor.as_function(), js_undefined(), &resolve_function, &reject_function);
|
|
|
|
if (auto* exception = vm.exception()) {
|
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
|
|
|
vm.clear_exception();
|
|
|
|
vm.stop_unwind();
|
2021-10-20 21:16:30 +01:00
|
|
|
TRY(vm.call(reject_function, js_undefined(), exception->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
|
|
|
}
|
|
|
|
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-19 20:18:01 +03:00
|
|
|
JS_DEFINE_OLD_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-10-12 19:24:57 +01:00
|
|
|
auto* constructor = TRY_OR_DISCARD(vm.this_value(global_object).to_object(global_object));
|
2021-08-21 13:41:32 -04:00
|
|
|
|
|
|
|
auto promise_capability = new_promise_capability(global_object, constructor);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
2021-10-20 22:35:43 -04:00
|
|
|
auto promise_resolve = TRY_OR_REJECT(vm, promise_capability, get_promise_resolve(global_object, constructor));
|
|
|
|
auto* iterator_record = TRY_OR_REJECT(vm, promise_capability, get_iterator(global_object, vm.argument(0)));
|
2021-08-21 13:41:32 -04:00
|
|
|
|
|
|
|
auto result = perform_promise_all(global_object, *iterator_record, constructor, promise_capability, promise_resolve);
|
2021-10-20 13:36:14 -04:00
|
|
|
if (auto* exception = vm.exception()) {
|
|
|
|
// FIXME: Once perform_promise_all returns a throw completion, pass that to iterator_close() instead.
|
|
|
|
auto result_error = throw_completion(exception->value());
|
|
|
|
|
|
|
|
if (!iterator_record_is_complete(global_object, *iterator_record)) {
|
|
|
|
TemporaryClearException clear_exception(vm); // iterator_close() may invoke vm.call(), which VERIFYs no exception.
|
|
|
|
result_error = iterator_close(*iterator_record, move(result_error));
|
|
|
|
}
|
2021-08-21 13:41:32 -04:00
|
|
|
|
2021-10-20 22:35:43 -04:00
|
|
|
TRY_OR_REJECT(vm, promise_capability, result_error);
|
2021-08-21 13:41:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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-19 20:18:01 +03:00
|
|
|
JS_DEFINE_OLD_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-10-12 19:24:57 +01:00
|
|
|
auto* constructor = TRY_OR_DISCARD(vm.this_value(global_object).to_object(global_object));
|
2021-08-21 17:00:48 -04:00
|
|
|
|
|
|
|
auto promise_capability = new_promise_capability(global_object, constructor);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
2021-10-20 22:35:43 -04:00
|
|
|
auto promise_resolve = TRY_OR_REJECT(vm, promise_capability, get_promise_resolve(global_object, constructor));
|
|
|
|
auto* iterator_record = TRY_OR_REJECT(vm, promise_capability, get_iterator(global_object, vm.argument(0)));
|
2021-08-21 17:00:48 -04:00
|
|
|
|
|
|
|
auto result = perform_promise_all_settled(global_object, *iterator_record, constructor, promise_capability, promise_resolve);
|
2021-10-20 13:36:14 -04:00
|
|
|
if (auto* exception = vm.exception()) {
|
|
|
|
// FIXME: Once perform_promise_all_settled returns a throw completion, pass that to iterator_close() instead.
|
|
|
|
auto result_error = throw_completion(exception->value());
|
|
|
|
|
|
|
|
if (!iterator_record_is_complete(global_object, *iterator_record)) {
|
|
|
|
TemporaryClearException clear_exception(vm); // iterator_close() may invoke vm.call(), which VERIFYs no exception.
|
|
|
|
result_error = iterator_close(*iterator_record, move(result_error));
|
|
|
|
}
|
2021-08-21 17:00:48 -04:00
|
|
|
|
2021-10-20 22:35:43 -04:00
|
|
|
TRY_OR_REJECT(vm, promise_capability, result_error);
|
2021-08-21 17:00:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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-19 20:18:01 +03:00
|
|
|
JS_DEFINE_OLD_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-10-12 19:24:57 +01:00
|
|
|
auto* constructor = TRY_OR_DISCARD(vm.this_value(global_object).to_object(global_object));
|
2021-08-21 16:43:38 -04:00
|
|
|
|
|
|
|
auto promise_capability = new_promise_capability(global_object, constructor);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
2021-10-20 22:35:43 -04:00
|
|
|
auto promise_resolve = TRY_OR_REJECT(vm, promise_capability, get_promise_resolve(global_object, constructor));
|
|
|
|
auto* iterator_record = TRY_OR_REJECT(vm, promise_capability, get_iterator(global_object, vm.argument(0)));
|
2021-08-21 16:43:38 -04:00
|
|
|
|
|
|
|
auto result = perform_promise_any(global_object, *iterator_record, constructor, promise_capability, promise_resolve);
|
2021-10-20 13:36:14 -04:00
|
|
|
if (auto* exception = vm.exception()) {
|
|
|
|
// FIXME: Once perform_promise_any returns a throw completion, pass that to iterator_close() instead.
|
|
|
|
auto result_error = throw_completion(exception->value());
|
|
|
|
|
|
|
|
if (!iterator_record_is_complete(global_object, *iterator_record)) {
|
|
|
|
TemporaryClearException clear_exception(vm); // iterator_close() may invoke vm.call(), which VERIFYs no exception.
|
|
|
|
result_error = iterator_close(*iterator_record, move(result_error));
|
|
|
|
}
|
2021-08-21 16:43:38 -04:00
|
|
|
|
2021-10-20 22:35:43 -04:00
|
|
|
TRY_OR_REJECT(vm, promise_capability, result_error);
|
2021-08-21 16:43:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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-19 20:18:01 +03:00
|
|
|
JS_DEFINE_OLD_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-10-12 19:24:57 +01:00
|
|
|
auto* constructor = TRY_OR_DISCARD(vm.this_value(global_object).to_object(global_object));
|
2021-08-21 17:12:24 -04:00
|
|
|
|
|
|
|
auto promise_capability = new_promise_capability(global_object, constructor);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
2021-10-20 22:35:43 -04:00
|
|
|
auto promise_resolve = TRY_OR_REJECT(vm, promise_capability, get_promise_resolve(global_object, constructor));
|
|
|
|
auto* iterator_record = TRY_OR_REJECT(vm, promise_capability, get_iterator(global_object, vm.argument(0)));
|
2021-08-21 17:12:24 -04:00
|
|
|
|
|
|
|
auto result = perform_promise_race(global_object, *iterator_record, constructor, promise_capability, promise_resolve);
|
2021-10-20 13:36:14 -04:00
|
|
|
if (auto* exception = vm.exception()) {
|
|
|
|
// FIXME: Once perform_promise_race returns a throw completion, pass that to iterator_close() instead.
|
|
|
|
auto result_error = throw_completion(exception->value());
|
|
|
|
|
|
|
|
if (!iterator_record_is_complete(global_object, *iterator_record)) {
|
|
|
|
TemporaryClearException clear_exception(vm);
|
|
|
|
result_error = iterator_close(*iterator_record, move(result_error)); // iterator_close() may invoke vm.call(), which VERIFYs no exception.
|
|
|
|
}
|
2021-08-21 17:12:24 -04:00
|
|
|
|
2021-10-20 22:35:43 -04:00
|
|
|
TRY_OR_REJECT(vm, promise_capability, result_error);
|
2021-08-21 17:12:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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-19 20:18:01 +03:00
|
|
|
JS_DEFINE_OLD_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-10-12 19:24:57 +01:00
|
|
|
auto* constructor = TRY_OR_DISCARD(vm.this_value(global_object).to_object(global_object));
|
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 promise_capability = new_promise_capability(global_object, constructor);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
auto reason = vm.argument(0);
|
2021-09-23 20:56:28 +03:00
|
|
|
[[maybe_unused]] auto result = TRY_OR_DISCARD(vm.call(*promise_capability.reject, js_undefined(), reason));
|
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_capability.promise;
|
|
|
|
}
|
|
|
|
|
2021-06-13 00:22:35 +01:00
|
|
|
// 27.2.4.7 Promise.resolve ( x ), https://tc39.es/ecma262/#sec-promise.resolve
|
2021-10-19 20:18:01 +03:00
|
|
|
JS_DEFINE_OLD_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
|
|
|
{
|
2021-10-12 19:24:57 +01:00
|
|
|
auto* constructor = TRY_OR_DISCARD(vm.this_value(global_object).to_object(global_object));
|
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);
|
|
|
|
return promise_resolve(global_object, *constructor, value);
|
|
|
|
}
|
|
|
|
|
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-19 20:18:01 +03:00
|
|
|
JS_DEFINE_OLD_NATIVE_FUNCTION(PromiseConstructor::symbol_species_getter)
|
2021-06-07 19:31:32 +03:00
|
|
|
{
|
|
|
|
return vm.this_value(global_object);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|