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
|
|
|
|
static Value get_promise_resolve(GlobalObject& global_object, Value constructor)
|
|
|
|
{
|
|
|
|
VERIFY(constructor.is_constructor());
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
|
|
|
auto promise_resolve = constructor.get(global_object, vm.names.resolve);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
if (!promise_resolve.is_function()) {
|
|
|
|
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, promise_resolve.to_string_without_side_effects());
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return promise_resolve;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise
|
|
|
|
static Optional<Value> if_abrupt_reject_promise(GlobalObject& global_object, Value, PromiseCapability capability)
|
|
|
|
{
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
|
|
|
if (auto* exception = vm.exception()) {
|
|
|
|
vm.clear_exception();
|
|
|
|
vm.stop_unwind();
|
|
|
|
|
|
|
|
(void)vm.call(*capability.reject, js_undefined(), exception->value());
|
|
|
|
return capability.promise;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
return iterator_complete(global_object, iterator_record);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
iterator_record.set(vm.names.done, Value(true), Object::ShouldThrowExceptions::No);
|
|
|
|
}
|
|
|
|
|
2021-08-21 16:31:55 -04:00
|
|
|
using EndOfElementsCallback = Function<Value(PromiseValueList&)>;
|
|
|
|
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) {
|
|
|
|
auto* next = iterator_step(global_object, iterator_record);
|
|
|
|
if (vm.exception()) {
|
|
|
|
set_iterator_record_complete(global_object, iterator_record);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
return end_of_list(*values);
|
2021-08-21 13:41:32 -04:00
|
|
|
return result_capability.promise;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto next_value = iterator_value(global_object, *next);
|
|
|
|
if (vm.exception()) {
|
|
|
|
set_iterator_record_complete(global_object, iterator_record);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
values->values.append(js_undefined());
|
|
|
|
|
|
|
|
auto next_promise = vm.call(promise_resolve.as_function(), constructor, next_value);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
++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,
|
|
|
|
[&](PromiseValueList& values) -> Value {
|
|
|
|
auto values_array = Array::create_from(global_object, values.values);
|
|
|
|
|
|
|
|
(void)vm.call(*result_capability.resolve, js_undefined(), values_array);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
return result_capability.promise;
|
|
|
|
},
|
|
|
|
[&](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 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,
|
|
|
|
[&](PromiseValueList& errors) -> Value {
|
|
|
|
auto errors_array = Array::create_from(global_object, errors.values);
|
|
|
|
|
|
|
|
auto* error = AggregateError::create(global_object);
|
|
|
|
error->define_property_or_throw(vm.names.errors, { .value = errors_array, .writable = true, .enumerable = false, .configurable = true });
|
|
|
|
|
|
|
|
vm.throw_exception(global_object, error);
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
[&](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);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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-08-21 13:41:32 -04:00
|
|
|
define_native_function(vm.names.all, all, 1, attr);
|
2021-08-21 16:43:38 -04:00
|
|
|
define_native_function(vm.names.any, any, 1, attr);
|
2021-06-02 21:06:21 +01:00
|
|
|
// TODO: Implement these functions below and uncomment this.
|
|
|
|
// define_native_function(vm.names.allSettled, all_settled, 1, attr);
|
|
|
|
// define_native_function(vm.names.race, race, 1, attr);
|
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
|
|
|
define_native_function(vm.names.reject, reject, 1, attr);
|
|
|
|
define_native_function(vm.names.resolve, resolve, 1, attr);
|
2021-06-07 19:31:32 +03:00
|
|
|
|
2021-06-25 18:37:14 +01:00
|
|
|
define_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
|
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
|
|
|
Value PromiseConstructor::call()
|
|
|
|
{
|
|
|
|
auto& vm = this->vm();
|
|
|
|
vm.throw_exception<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, vm.names.Promise);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2021-06-13 00:22:35 +01:00
|
|
|
// 27.2.3.1 Promise ( executor ), https://tc39.es/ecma262/#sec-promise-executor
|
2021-06-27 21:48:34 +02:00
|
|
|
Value 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);
|
|
|
|
if (!executor.is_function()) {
|
2021-06-20 01:09:39 +01:00
|
|
|
vm.throw_exception<TypeError>(global_object, ErrorType::PromiseExecutorNotAFunction);
|
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 {};
|
|
|
|
}
|
2021-06-20 01:09:39 +01:00
|
|
|
|
|
|
|
auto* promise = ordinary_create_from_constructor<Promise>(global_object, new_target, &GlobalObject::promise_prototype);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
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-07-05 13:10:04 +01:00
|
|
|
(void)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
|
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
|
|
|
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::all)
|
|
|
|
{
|
2021-08-21 13:41:32 -04:00
|
|
|
auto* constructor = vm.this_value(global_object).to_object(global_object);
|
|
|
|
if (!constructor)
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto promise_capability = new_promise_capability(global_object, constructor);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto promise_resolve = get_promise_resolve(global_object, constructor);
|
|
|
|
if (auto abrupt = if_abrupt_reject_promise(global_object, promise_resolve, promise_capability); abrupt.has_value())
|
|
|
|
return abrupt.value();
|
|
|
|
|
|
|
|
auto iterator_record = get_iterator(global_object, vm.argument(0));
|
|
|
|
if (auto abrupt = if_abrupt_reject_promise(global_object, iterator_record, promise_capability); abrupt.has_value())
|
|
|
|
return abrupt.value();
|
|
|
|
|
|
|
|
auto result = perform_promise_all(global_object, *iterator_record, constructor, promise_capability, promise_resolve);
|
|
|
|
if (vm.exception()) {
|
|
|
|
if (!iterator_record_is_complete(global_object, *iterator_record))
|
|
|
|
iterator_close(*iterator_record);
|
|
|
|
|
|
|
|
auto abrupt = if_abrupt_reject_promise(global_object, result, promise_capability);
|
|
|
|
return abrupt.value();
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
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
|
|
|
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::all_settled)
|
|
|
|
{
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
2021-06-13 00:22:35 +01:00
|
|
|
// 27.2.4.3 Promise.any ( iterable ), https://tc39.es/ecma262/#sec-promise.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
|
|
|
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::any)
|
|
|
|
{
|
2021-08-21 16:43:38 -04:00
|
|
|
auto* constructor = vm.this_value(global_object).to_object(global_object);
|
|
|
|
if (!constructor)
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto promise_capability = new_promise_capability(global_object, constructor);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto promise_resolve = get_promise_resolve(global_object, constructor);
|
|
|
|
if (auto abrupt = if_abrupt_reject_promise(global_object, promise_resolve, promise_capability); abrupt.has_value())
|
|
|
|
return abrupt.value();
|
|
|
|
|
|
|
|
auto iterator_record = get_iterator(global_object, vm.argument(0));
|
|
|
|
if (auto abrupt = if_abrupt_reject_promise(global_object, iterator_record, promise_capability); abrupt.has_value())
|
|
|
|
return abrupt.value();
|
|
|
|
|
|
|
|
auto result = perform_promise_any(global_object, *iterator_record, constructor, promise_capability, promise_resolve);
|
|
|
|
if (vm.exception()) {
|
|
|
|
if (!iterator_record_is_complete(global_object, *iterator_record))
|
|
|
|
iterator_close(*iterator_record);
|
|
|
|
|
|
|
|
auto abrupt = if_abrupt_reject_promise(global_object, result, promise_capability);
|
|
|
|
return abrupt.value();
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
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
|
|
|
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::race)
|
|
|
|
{
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
2021-06-13 00:22:35 +01:00
|
|
|
// 27.2.4.6 Promise.reject ( r ), https://tc39.es/ecma262/#sec-promise.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
|
|
|
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::reject)
|
|
|
|
{
|
|
|
|
auto* constructor = vm.this_value(global_object).to_object(global_object);
|
|
|
|
if (!constructor)
|
|
|
|
return {};
|
|
|
|
auto promise_capability = new_promise_capability(global_object, constructor);
|
|
|
|
if (vm.exception())
|
|
|
|
return {};
|
|
|
|
auto reason = vm.argument(0);
|
|
|
|
[[maybe_unused]] auto result = vm.call(*promise_capability.reject, js_undefined(), reason);
|
|
|
|
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
|
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
|
|
|
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::resolve)
|
|
|
|
{
|
|
|
|
auto* constructor = vm.this_value(global_object).to_object(global_object);
|
|
|
|
if (!constructor)
|
|
|
|
return {};
|
|
|
|
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-06-07 19:31:32 +03:00
|
|
|
JS_DEFINE_NATIVE_GETTER(PromiseConstructor::symbol_species_getter)
|
|
|
|
{
|
|
|
|
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
|
|
|
}
|