[njs] Added remaining Promise constructor methods.
Alexander Borisov
alexander.borisov at nginx.com
Wed Aug 11 18:49:55 UTC 2021
details: https://hg.nginx.org/njs/rev/80adcb502e40
branches:
changeset: 1686:80adcb502e40
user: Alexander Borisov <alexander.borisov at nginx.com>
date: Wed Aug 11 21:48:52 2021 +0300
description:
Added remaining Promise constructor methods.
The following methods were added: Promise.all(), Promise.allSettled(),
Promise.any(), Promise.race().
diffstat:
src/njs_promise.c | 599 +++++++++++++++++++++++++++++++++++
test/js/promise_all.js | 9 +
test/js/promise_allSettled.js | 20 +
test/js/promise_allSettled_string.js | 10 +
test/js/promise_all_throw.js | 9 +
test/js/promise_any.js | 8 +
test/js/promise_any_all_rejected.js | 7 +
test/js/promise_race.js | 12 +
test/js/promise_race_throw.js | 12 +
test/njs_expect_test.exp | 24 +
10 files changed, 710 insertions(+), 0 deletions(-)
diffs (793 lines):
diff -r 3e00ce537115 -r 80adcb502e40 src/njs_promise.c
--- a/src/njs_promise.c Wed Aug 11 21:48:51 2021 +0300
+++ b/src/njs_promise.c Wed Aug 11 21:48:52 2021 +0300
@@ -1,5 +1,6 @@
/*
+ * Copyright (C) Alexander Borisov
* Copyright (C) Nginx, Inc.
*/
@@ -17,6 +18,12 @@ typedef enum {
NJS_PROMISE_REJECT
} njs_promise_rejection_type_t;
+typedef enum {
+ NJS_PROMISE_ALL = 0,
+ NJS_PROMISE_ALL_SETTLED,
+ NJS_PROMISE_ANY
+} njs_promise_function_type_t;
+
typedef struct {
njs_promise_type_t state;
njs_value_t result;
@@ -48,6 +55,22 @@ typedef struct {
njs_function_native_t handler;
} njs_promise_context_t;
+typedef struct {
+ njs_bool_t already_called;
+ uint32_t index;
+ uint32_t *remaining_elements;
+ njs_array_t *values;
+ njs_promise_capability_t *capability;
+} njs_promise_all_context_t;
+
+typedef struct {
+ njs_iterator_args_t args;
+ uint32_t *remaining;
+ njs_value_t *constructor;
+ njs_function_t *function;
+ njs_promise_capability_t *capability;
+} njs_promise_iterator_args_t;
+
static njs_promise_t *njs_promise_constructor_call(njs_vm_t *vm,
njs_function_t *function);
@@ -78,6 +101,28 @@ static njs_int_t njs_promise_reaction_jo
njs_uint_t nargs, njs_index_t unused);
static njs_int_t njs_promise_resolve_thenable_job(njs_vm_t *vm,
njs_value_t *args, njs_uint_t nargs, njs_index_t unused);
+static njs_int_t njs_promise_perform_all(njs_vm_t *vm, njs_value_t *iterator,
+ njs_promise_iterator_args_t *pargs, njs_iterator_handler_t handler,
+ njs_value_t *retval);
+static njs_int_t njs_promise_perform_all_handler(njs_vm_t *vm,
+ njs_iterator_args_t *args, njs_value_t *value, int64_t index);
+static njs_int_t njs_promise_all_resolve_element_functions(njs_vm_t *vm,
+ njs_value_t *args, njs_uint_t nargs, njs_index_t unused);
+static njs_int_t njs_promise_perform_all_settled_handler(njs_vm_t *vm,
+ njs_iterator_args_t *args, njs_value_t *value, int64_t index);
+static njs_int_t njs_promise_all_settled_element_functions(njs_vm_t *vm,
+ njs_value_t *args, njs_uint_t nargs, njs_index_t rejected);
+static njs_int_t njs_promise_perform_any_handler(njs_vm_t *vm,
+ njs_iterator_args_t *args, njs_value_t *value, int64_t index);
+static njs_int_t njs_promise_any_reject_element_functions(njs_vm_t *vm,
+ njs_value_t *args, njs_uint_t nargs, njs_index_t unused);
+static njs_int_t njs_promise_perform_race_handler(njs_vm_t *vm,
+ njs_iterator_args_t *args, njs_value_t *value, int64_t index);
+
+
+static const njs_value_t string_resolve = njs_string("resolve");
+static const njs_value_t string_any_rejected =
+ njs_long_string("All promises were rejected");
static njs_promise_t *
@@ -1229,6 +1274,527 @@ njs_promise_resolve_thenable_job(njs_vm_
static njs_int_t
+njs_promise_all(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t function_type)
+{
+ njs_int_t ret;
+ njs_value_t *promise, resolve;
+ njs_iterator_handler_t handler;
+ njs_promise_iterator_args_t pargs;
+
+ promise = njs_argument(args, 0);
+
+ pargs.capability = njs_promise_new_capability(vm, promise);
+ if (njs_slow_path(pargs.capability == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_property(vm, promise, njs_value_arg(&string_resolve),
+ &resolve);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_slow_path(!njs_is_function(&resolve))) {
+ njs_type_error(vm, "resolve is not callable");
+ return NJS_ERROR;
+ }
+
+ pargs.function = njs_function(&resolve);
+ pargs.constructor = promise;
+
+ switch (function_type) {
+ case NJS_PROMISE_ALL_SETTLED:
+ handler = njs_promise_perform_all_settled_handler;
+ break;
+
+ case NJS_PROMISE_ANY:
+ handler = njs_promise_perform_any_handler;
+ break;
+
+ default:
+ handler = njs_promise_perform_all_handler;
+ break;
+ }
+
+ return njs_promise_perform_all(vm, njs_arg(args, nargs, 1), &pargs,
+ handler, &vm->retval);
+}
+
+
+static njs_int_t
+njs_promise_perform_all(njs_vm_t *vm, njs_value_t *iterator,
+ njs_promise_iterator_args_t *pargs, njs_iterator_handler_t handler,
+ njs_value_t *retval)
+{
+ int64_t length;
+ njs_int_t ret;
+ njs_value_t argument;
+ njs_object_t *error;
+
+ if (njs_slow_path(!njs_is_object(pargs->constructor))) {
+ njs_type_error(vm, "constructor is not object");
+ return NJS_ERROR;
+ }
+
+ njs_memzero(&pargs->args, sizeof(njs_iterator_args_t));
+
+ ret = njs_object_length(vm, iterator, &length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ pargs->args.array = njs_array_alloc(vm, 1, length, 0);
+ if (njs_slow_path(pargs->args.array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ pargs->remaining = njs_mp_alloc(vm->mem_pool, sizeof(uint32_t));
+ if (njs_slow_path(pargs->remaining == NULL)) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ (*pargs->remaining) = 1;
+
+ pargs->args.value = iterator;
+ pargs->args.to = length;
+
+ ret = njs_object_iterate(vm, &pargs->args, handler);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (--(*pargs->remaining) == 0) {
+ njs_mp_free(vm->mem_pool, pargs->remaining);
+
+ njs_set_array(&argument, pargs->args.array);
+
+ if (handler == njs_promise_perform_any_handler) {
+ error = njs_error_alloc(vm, NJS_OBJ_TYPE_AGGREGATE_ERROR,
+ NULL, &string_any_rejected, &argument);
+ if (njs_slow_path(error == NULL)) {
+ return NJS_ERROR;
+ }
+
+ njs_set_object(&argument, error);
+ }
+
+ ret = njs_function_call(vm, njs_function(&pargs->capability->resolve),
+ &njs_value_undefined, &argument, 1, retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+ }
+
+ *retval = pargs->capability->promise;
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_promise_perform_all_handler(njs_vm_t *vm, njs_iterator_args_t *args,
+ njs_value_t *value, int64_t index)
+{
+ njs_int_t ret;
+ njs_value_t arguments[2], next;
+ njs_function_t *on_fulfilled;
+ njs_promise_capability_t *capability;
+ njs_promise_all_context_t *context;
+ njs_promise_iterator_args_t *pargs;
+
+ pargs = (njs_promise_iterator_args_t *) args;
+
+ capability = pargs->capability;
+
+ njs_set_undefined(&pargs->args.array->start[index]);
+
+ ret = njs_function_call(vm, pargs->function, pargs->constructor, value,
+ 1, &next);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ on_fulfilled = njs_promise_create_function(vm,
+ sizeof(njs_promise_all_context_t));
+ if (njs_slow_path(on_fulfilled == NULL)) {
+ return NJS_ERROR;
+ }
+
+ on_fulfilled->u.native = njs_promise_all_resolve_element_functions;
+ on_fulfilled->args_count = 1;
+
+ context = on_fulfilled->context;
+
+ context->already_called = 0;
+ context->index = (uint32_t) index;
+ context->values = pargs->args.array;
+ context->capability = capability;
+ context->remaining_elements = pargs->remaining;
+
+ (*pargs->remaining)++;
+
+ njs_set_function(&arguments[0], on_fulfilled);
+ arguments[1] = capability->reject;
+
+ ret = njs_promise_invoke_then(vm, &next, arguments, 2);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_promise_all_resolve_element_functions(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ njs_value_t arguments;
+ njs_promise_all_context_t *context;
+
+ context = vm->top_frame->function->context;
+
+ if (context->already_called) {
+ njs_vm_retval_set(vm, &njs_value_undefined);
+ return NJS_OK;
+ }
+
+ context->already_called = 1;
+ context->values->start[context->index] = *njs_arg(args, nargs, 1);
+
+ if (--(*context->remaining_elements) == 0) {
+ njs_mp_free(vm->mem_pool, context->remaining_elements);
+
+ njs_set_array(&arguments, context->values);
+
+ return njs_function_call(vm,
+ njs_function(&context->capability->resolve),
+ &njs_value_undefined, &arguments, 1,
+ &vm->retval);
+ }
+
+ njs_vm_retval_set(vm, &njs_value_undefined);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_promise_perform_all_settled_handler(njs_vm_t *vm, njs_iterator_args_t *args,
+ njs_value_t *value, int64_t index)
+{
+ njs_int_t ret;
+ njs_value_t arguments[2], next;
+ njs_function_t *on_fulfilled, *on_rejected;
+ njs_promise_capability_t *capability;
+ njs_promise_all_context_t *context;
+ njs_promise_iterator_args_t *pargs;
+
+ pargs = (njs_promise_iterator_args_t *) args;
+
+ capability = pargs->capability;
+
+ njs_set_undefined(&pargs->args.array->start[index]);
+
+ ret = njs_function_call(vm, pargs->function, pargs->constructor, value,
+ 1, &next);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ on_fulfilled = njs_promise_create_function(vm,
+ sizeof(njs_promise_all_context_t));
+ if (njs_slow_path(on_fulfilled == NULL)) {
+ return NJS_ERROR;
+ }
+
+ context = on_fulfilled->context;
+
+ context->already_called = 0;
+ context->index = (uint32_t) index;
+ context->values = pargs->args.array;
+ context->capability = capability;
+ context->remaining_elements = pargs->remaining;
+
+ on_rejected = njs_promise_create_function(vm, 0);
+ if (njs_slow_path(on_rejected == NULL)) {
+ return NJS_ERROR;
+ }
+
+ on_fulfilled->u.native = njs_promise_all_settled_element_functions;
+ on_rejected->u.native = njs_promise_all_settled_element_functions;
+ on_rejected->magic8 = 1; /* rejected. */
+
+ on_fulfilled->args_count = 1;
+ on_rejected->args_count = 1;
+
+ on_rejected->context = context;
+
+ (*pargs->remaining)++;
+
+ njs_set_function(&arguments[0], on_fulfilled);
+ njs_set_function(&arguments[1], on_rejected);
+
+ ret = njs_promise_invoke_then(vm, &next, arguments, 2);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_promise_all_settled_element_functions(njs_vm_t *vm,
+ njs_value_t *args, njs_uint_t nargs, njs_index_t rejected)
+{
+ njs_int_t ret;
+ njs_value_t arguments, *value;
+ njs_object_t *obj;
+ const njs_value_t *status, *set;
+ njs_promise_all_context_t *context;
+
+ static const njs_value_t string_status = njs_string("status");
+ static const njs_value_t string_fulfilled = njs_string("fulfilled");
+ static const njs_value_t string_value = njs_string("value");
+ static const njs_value_t string_rejected = njs_string("rejected");
+ static const njs_value_t string_reason = njs_string("reason");
+
+ context = vm->top_frame->function->context;
+
+ if (context->already_called) {
+ njs_vm_retval_set(vm, &njs_value_undefined);
+ return NJS_OK;
+ }
+
+ context->already_called = 1;
+
+ obj = njs_object_alloc(vm);
+ if (njs_slow_path(obj == NULL)) {
+ return NJS_ERROR;
+ }
+
+ value = &context->values->start[context->index];
+
+ njs_set_object(value, obj);
+
+ if (rejected) {
+ status = &string_rejected;
+ set = &string_reason;
+
+ } else {
+ status = &string_fulfilled;
+ set = &string_value;
+ }
+
+ ret = njs_value_property_set(vm, value, njs_value_arg(&string_status),
+ njs_value_arg(status));
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ ret = njs_value_property_set(vm, value, njs_value_arg(set),
+ njs_arg(args, nargs, 1));
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (--(*context->remaining_elements) == 0) {
+ njs_mp_free(vm->mem_pool, context->remaining_elements);
+
+ njs_set_array(&arguments, context->values);
+
+ return njs_function_call(vm,
+ njs_function(&context->capability->resolve),
+ &njs_value_undefined, &arguments, 1,
+ &vm->retval);
+ }
+
+ njs_vm_retval_set(vm, &njs_value_undefined);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_promise_perform_any_handler(njs_vm_t *vm, njs_iterator_args_t *args,
+ njs_value_t *value, int64_t index)
+{
+ njs_int_t ret;
+ njs_value_t arguments[2], next;
+ njs_function_t *on_rejected;
+ njs_promise_capability_t *capability;
+ njs_promise_all_context_t *context;
+ njs_promise_iterator_args_t *pargs;
+
+ pargs = (njs_promise_iterator_args_t *) args;
+
+ capability = pargs->capability;
+
+ njs_set_undefined(&pargs->args.array->start[index]);
+
+ ret = njs_function_call(vm, pargs->function, pargs->constructor, value, 1,
+ &next);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ on_rejected = njs_promise_create_function(vm,
+ sizeof(njs_promise_all_context_t));
+ if (njs_slow_path(on_rejected == NULL)) {
+ return NJS_ERROR;
+ }
+
+ on_rejected->u.native = njs_promise_any_reject_element_functions;
+ on_rejected->args_count = 1;
+
+ context = on_rejected->context;
+
+ context->already_called = 0;
+ context->index = (uint32_t) index;
+ context->values = pargs->args.array;
+ context->capability = capability;
+ context->remaining_elements = pargs->remaining;
+
+ (*pargs->remaining)++;
+
+ arguments[0] = capability->resolve;
+ njs_set_function(&arguments[1], on_rejected);
+
+ ret = njs_promise_invoke_then(vm, &next, arguments, 2);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_promise_any_reject_element_functions(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ njs_value_t argument;
+ njs_object_t *error;
+ njs_promise_all_context_t *context;
+
+ context = vm->top_frame->function->context;
+
+ if (context->already_called) {
+ njs_vm_retval_set(vm, &njs_value_undefined);
+ return NJS_OK;
+ }
+
+ context->already_called = 1;
+ context->values->start[context->index] = *njs_arg(args, nargs, 1);
+
+ if (--(*context->remaining_elements) == 0) {
+ njs_mp_free(vm->mem_pool, context->remaining_elements);
+
+ njs_set_array(&argument, context->values);
+
+ error = njs_error_alloc(vm, NJS_OBJ_TYPE_AGGREGATE_ERROR,
+ NULL, &string_any_rejected, &argument);
+ if (njs_slow_path(error == NULL)) {
+ return NJS_ERROR;
+ }
+
+ njs_set_object(&argument, error);
+
+ return njs_function_call(vm, njs_function(&context->capability->reject),
+ &njs_value_undefined, &argument, 1,
+ &vm->retval);
+ }
+
+ njs_vm_retval_set(vm, &njs_value_undefined);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_promise_race(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ int64_t length;
+ njs_int_t ret;
+ njs_value_t *promise, *iterator, resolve;
+ njs_promise_iterator_args_t pargs;
+
+ promise = njs_argument(args, 0);
+ iterator = njs_arg(args, nargs, 1);
+
+ pargs.capability = njs_promise_new_capability(vm, promise);
+ if (njs_slow_path(pargs.capability == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_property(vm, promise, njs_value_arg(&string_resolve),
+ &resolve);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_slow_path(!njs_is_function(&resolve))) {
+ njs_type_error(vm, "resolve is not callable");
+ return NJS_ERROR;
+ }
+
+ ret = njs_object_length(vm, iterator, &length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ njs_memzero(&pargs.args, sizeof(njs_iterator_args_t));
+
+ pargs.function = njs_function(&resolve);
+ pargs.constructor = promise;
+
+ pargs.args.value = iterator;
+ pargs.args.to = length;
+
+ ret = njs_object_iterate(vm, &pargs.args, njs_promise_perform_race_handler);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ vm->retval = pargs.capability->promise;
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_promise_perform_race_handler(njs_vm_t *vm, njs_iterator_args_t *args,
+ njs_value_t *value, int64_t index)
+{
+ njs_int_t ret;
+ njs_value_t arguments[2], next;
+ njs_promise_capability_t *capability;
+ njs_promise_iterator_args_t *pargs;
+
+ pargs = (njs_promise_iterator_args_t *) args;
+
+ ret = njs_function_call(vm, pargs->function, pargs->constructor, value,
+ 1, &next);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ capability = pargs->capability;
+
+ arguments[0] = capability->resolve;
+ arguments[1] = capability->reject;
+
+ (void) njs_promise_invoke_then(vm, &next, arguments, 2);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
njs_promise_species(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
@@ -1278,6 +1844,39 @@ static const njs_object_prop_t njs_prom
{
.type = NJS_PROPERTY,
+ .name = njs_string("all"),
+ .value = njs_native_function2(njs_promise_all, 1, NJS_PROMISE_ALL),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("allSettled"),
+ .value = njs_native_function2(njs_promise_all, 1,
+ NJS_PROMISE_ALL_SETTLED),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("any"),
+ .value = njs_native_function2(njs_promise_all, 1, NJS_PROMISE_ANY),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("race"),
+ .value = njs_native_function(njs_promise_race, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
.name = njs_wellknown_symbol(NJS_SYMBOL_SPECIES),
.value = njs_value(NJS_INVALID, 1, NAN),
.getter = njs_native_function(njs_promise_species, 0),
diff -r 3e00ce537115 -r 80adcb502e40 test/js/promise_all.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/promise_all.js Wed Aug 11 21:48:52 2021 +0300
@@ -0,0 +1,9 @@
+function resolve(value) {
+ return new Promise(resolve => setTimeout(() => resolve(value), 0));
+}
+
+Promise.all([resolve(['one', 'two']), resolve(['three', 'four'])])
+.then(
+ (v) => {console.log(`resolved:${njs.dump(v)}`)},
+ (v) => {console.log(`rejected:${njs.dump(v)}`)}
+);
diff -r 3e00ce537115 -r 80adcb502e40 test/js/promise_allSettled.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/promise_allSettled.js Wed Aug 11 21:48:52 2021 +0300
@@ -0,0 +1,20 @@
+var p0 = Promise.resolve(2).then(v => v + 1);
+var p1 = Promise.reject(21).catch(v => v * 2);
+var p2 = Promise.resolve('nope').then(() => { throw 'foo' });
+var p3 = Promise.reject('yes').then(() => { throw 'nope'; });
+var p4 = Promise.resolve('here').finally(() => 'nope');
+var p5 = Promise.reject('here too').finally(() => 'nope');
+var p6 = Promise.resolve('nope').finally(() => { throw 'finally'; });
+var p7 = Promise.reject('nope').finally(() => { throw 'finally after rejected'; });
+var p8 = Promise.reject(1).then(() => 'nope', () => 0);
+
+function dump(v) {
+ var fulfilled = v.filter(v=>v.status == 'fulfilled').map(v=>v.value).sort();
+ var rejected = v.filter(v=>v.status == 'rejected').map(v=>v.reason).sort();
+ return `F:${fulfilled}|R:${rejected}`
+}
+
+Promise.allSettled([p0, p1, p2, p3, p4, p5, p6, p7, p8]).then(
+ (v) => {console.log(`resolved:${dump(v)}`)},
+ (v) => {console.log(`rejected:${dump(v)}`)}
+);
diff -r 3e00ce537115 -r 80adcb502e40 test/js/promise_allSettled_string.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/promise_allSettled_string.js Wed Aug 11 21:48:52 2021 +0300
@@ -0,0 +1,10 @@
+function dump(v) {
+ var fulfilled = v.filter(v=>v.status == 'fulfilled').map(v=>v.value).sort();
+ var rejected = v.filter(v=>v.status == 'rejected').map(v=>v.reason).sort();
+ return `F:${fulfilled}|R:${rejected}`;
+}
+
+Promise.allSettled("abc").then(
+ (v) => {console.log(`resolved:${dump(v)}`)},
+ (v) => {console.log(`rejected:${dump(v)}`)}
+);
diff -r 3e00ce537115 -r 80adcb502e40 test/js/promise_all_throw.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/promise_all_throw.js Wed Aug 11 21:48:52 2021 +0300
@@ -0,0 +1,9 @@
+var p0 = Promise.resolve(1).then(v => v + 1);
+var p1 = Promise.reject(2).catch(v => v * 2);
+var p2 = Promise.resolve().then(() => { throw 'foo' });
+var p3 = Promise.reject().then(() => { throw 'oof'; });
+
+Promise.all([p0, p1, p2, p3]).then(
+ (v) => {console.log(`resolved:${v}`)},
+ (v) => {console.log(`rejected:${v}`)}
+);
diff -r 3e00ce537115 -r 80adcb502e40 test/js/promise_any.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/promise_any.js Wed Aug 11 21:48:52 2021 +0300
@@ -0,0 +1,8 @@
+var p0 = Promise.resolve().then(() => { throw 'foo' });
+var p1 = Promise.reject(2).catch(v => v * 2);
+var p2 = Promise.resolve(1).then(v => v + 1);
+
+Promise.any([p0, p1, p2]).then(
+ (v) => {console.log(`resolved:${v}`)},
+ (v) => {console.log(`rejected:${v}`)}
+);
diff -r 3e00ce537115 -r 80adcb502e40 test/js/promise_any_all_rejected.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/promise_any_all_rejected.js Wed Aug 11 21:48:52 2021 +0300
@@ -0,0 +1,7 @@
+var p0 = Promise.reject(1);
+var p1 = Promise.reject(2);
+
+Promise.any([p0, p1]).then(
+ (v) => {console.log(`resolve:${v}`)},
+ (v) => {console.log(`reject:${v}`)}
+);
diff -r 3e00ce537115 -r 80adcb502e40 test/js/promise_race.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/promise_race.js Wed Aug 11 21:48:52 2021 +0300
@@ -0,0 +1,12 @@
+var p1 = new Promise((resolve, reject) => {
+ setTimeout(resolve, 0, 'one');
+});
+
+var p2 = new Promise((resolve, reject) => {
+ setTimeout(resolve, 0, 'two');
+});
+
+Promise.race([p1, p2]).then(
+ (v) => {console.log(`resolved:${v}`)},
+ (v) => {console.log(`rejected:${v}`)}
+);
diff -r 3e00ce537115 -r 80adcb502e40 test/js/promise_race_throw.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/promise_race_throw.js Wed Aug 11 21:48:52 2021 +0300
@@ -0,0 +1,12 @@
+var p1 = new Promise((resolve, reject) => {
+ throw 'one';
+});
+
+var p2 = new Promise((resolve, reject) => {
+ setTimeout(resolve, 0, 'two');
+});
+
+Promise.race([p1, p2]).then(
+ (v) => {console.log(`resolved:${v}`)},
+ (v) => {console.log(`rejected:${v}`)}
+);
diff -r 3e00ce537115 -r 80adcb502e40 test/njs_expect_test.exp
--- a/test/njs_expect_test.exp Wed Aug 11 21:48:51 2021 +0300
+++ b/test/njs_expect_test.exp Wed Aug 11 21:48:52 2021 +0300
@@ -1084,3 +1084,27 @@ njs_run {"./test/js/promise_reject_catch
njs_run {"./test/js/promise_reject_post_catch.js"} \
"Error: unhandled promise rejection: undefined"
+
+njs_run {"./test/js/promise_all.js"} \
+"resolved:\\\[\\\['one','two'],\\\['three','four']]"
+
+njs_run {"./test/js/promise_all_throw.js"} \
+"rejected:foo"
+
+njs_run {"./test/js/promise_allSettled.js"} \
+"resolved:resolved:F:0,3,42,here|R:finally,finally after rejected,foo,here too,yes"
+
+njs_run {"./test/js/promise_allSettled_string.js"} \
+"resolved:F:a,b,c|R:"
+
+njs_run {"./test/js/promise_any.js"} \
+"resolved:4"
+
+njs_run {"./test/js/promise_any_all_rejected.js"} \
+"reject:AggregateError: All promises were rejected"
+
+njs_run {"./test/js/promise_race.js"} \
+"resolved:one"
+
+njs_run {"./test/js/promise_race_throw.js"} \
+"rejected:one"
More information about the nginx-devel
mailing list