[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