diff --git a/src/org/mozilla/javascript/NativePromise.java b/src/org/mozilla/javascript/NativePromise.java index 05d79efeeb..e92260c8d6 100644 --- a/src/org/mozilla/javascript/NativePromise.java +++ b/src/org/mozilla/javascript/NativePromise.java @@ -44,6 +44,8 @@ public static void init(Context cx, Scriptable scope, boolean sealed) { scope, "reject", 1, NativePromise::reject, DONTENUM, DONTENUM | READONLY); constructor.defineConstructorMethod( scope, "all", 1, NativePromise::all, DONTENUM, DONTENUM | READONLY); + constructor.defineConstructorMethod( + scope, "allSettled", 1, NativePromise::allSettled, DONTENUM, DONTENUM | READONLY); constructor.defineConstructorMethod( scope, "race", 1, NativePromise::race, DONTENUM, DONTENUM | READONLY); @@ -160,8 +162,8 @@ private static Object reject(Context cx, Scriptable scope, Scriptable thisObj, O return cap.promise; } - // Promise.all - private static Object all(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + private static Object doAll( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args, boolean failFast) { Capability cap = new Capability(cx, scope, thisObj); Object arg = (args.length > 0 ? args[0] : Undefined.instance); @@ -180,7 +182,7 @@ private static Object all(Context cx, Scriptable scope, Scriptable thisObj, Obje IteratorLikeIterable.Itr iterator = iterable.iterator(); try { - PromiseAllResolver resolver = new PromiseAllResolver(iterator, thisObj, cap); + PromiseAllResolver resolver = new PromiseAllResolver(iterator, thisObj, cap, failFast); try { return resolver.resolve(cx, scope); } finally { @@ -198,6 +200,17 @@ private static Object all(Context cx, Scriptable scope, Scriptable thisObj, Obje } } + // Promise.all + private static Object all(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + return doAll(cx, scope, thisObj, args, true); + } + + // Promise.allSettled + private static Object allSettled( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + return doAll(cx, scope, thisObj, args, false); + } + // Promise.race private static Object race(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { Capability cap = new Capability(cx, scope, thisObj); @@ -691,11 +704,17 @@ private static class PromiseAllResolver { IteratorLikeIterable.Itr iterator; Scriptable thisObj; Capability capability; + boolean failFast; - PromiseAllResolver(IteratorLikeIterable.Itr iter, Scriptable thisObj, Capability cap) { + PromiseAllResolver( + IteratorLikeIterable.Itr iter, + Scriptable thisObj, + Capability cap, + boolean failFast) { this.iterator = iter; this.thisObj = thisObj; this.capability = cap; + this.failFast = failFast; } Object resolve(Context topCx, Scriptable topScope) { @@ -745,13 +764,42 @@ Object resolve(Context topCx, Scriptable topScope) { new LambdaFunction( topScope, 1, - (Context cx, Scriptable scope, Scriptable thisObj, Object[] args) -> - eltResolver.resolve( - cx, - scope, - (args.length > 0 ? args[0] : Undefined.instance), - this)); + (Context cx, + Scriptable scope, + Scriptable thisObj, + Object[] args) -> { + Object value = (args.length > 0 ? args[0] : Undefined.instance); + if (!failFast) { + Scriptable elementResult = cx.newObject(scope); + elementResult.put("status", elementResult, "fulfilled"); + elementResult.put("value", elementResult, value); + value = elementResult; + } + return eltResolver.resolve(cx, scope, value, this); + }); resolveFunc.setStandardPropertyAttributes(DONTENUM | READONLY); + + Callable rejectFunc = capability.reject; + if (!failFast) { + LambdaFunction resolveSettledRejection = + new LambdaFunction( + topScope, + 1, + (Context cx, + Scriptable scope, + Scriptable thisObj, + Object[] args) -> { + Scriptable result = cx.newObject(scope); + result.put("status", result, " rejected"); + result.put( + "reason", + result, + (args.length > 0 ? args[0] : Undefined.instance)); + return eltResolver.resolve(cx, scope, result, this); + }); + resolveSettledRejection.setStandardPropertyAttributes(DONTENUM | READONLY); + rejectFunc = resolveSettledRejection; + } remainingElements++; // Call "then" on the promise with the resolution func @@ -761,7 +809,7 @@ Object resolve(Context topCx, Scriptable topScope) { topCx, topScope, ScriptRuntime.lastStoredScriptable(topCx), - new Object[] {resolveFunc, capability.reject}); + new Object[] {resolveFunc, rejectFunc}); index++; } } diff --git a/testsrc/test262.properties b/testsrc/test262.properties index b5955c3272..7906a84e5d 100644 --- a/testsrc/test262.properties +++ b/testsrc/test262.properties @@ -978,34 +978,18 @@ built-ins/parseInt 3/60 (5.0%) S15.1.2.2_A2_T10_U180E.js {unsupported: [u180e]} S15.1.2.2_A9.2.js -built-ins/Promise 444/599 (74.12%) - allSettled/call-resolve-element.js - allSettled/call-resolve-element-after-return.js - allSettled/call-resolve-element-items.js - allSettled/capability-executor-called-twice.js - allSettled/capability-executor-not-callable.js - allSettled/capability-resolve-throws-no-close.js +built-ins/Promise 406/599 (67.78%) allSettled/capability-resolve-throws-reject.js {unsupported: [async]} allSettled/ctx-ctor.js {unsupported: [class]} - allSettled/ctx-ctor-throws.js allSettled/does-not-invoke-array-setters.js {unsupported: [async]} - allSettled/invoke-resolve.js - allSettled/invoke-resolve-error-close.js allSettled/invoke-resolve-error-reject.js {unsupported: [async]} allSettled/invoke-resolve-get-error.js {unsupported: [async]} allSettled/invoke-resolve-get-error-reject.js {unsupported: [async]} - allSettled/invoke-resolve-get-once-multiple-calls.js - allSettled/invoke-resolve-get-once-no-calls.js allSettled/invoke-resolve-on-promises-every-iteration-of-custom.js {unsupported: [class, async]} allSettled/invoke-resolve-on-promises-every-iteration-of-promise.js {unsupported: [async]} allSettled/invoke-resolve-on-values-every-iteration-of-promise.js {unsupported: [async]} - allSettled/invoke-resolve-return.js - allSettled/invoke-then.js - allSettled/invoke-then-error-close.js allSettled/invoke-then-error-reject.js {unsupported: [async]} - allSettled/invoke-then-get-error-close.js allSettled/invoke-then-get-error-reject.js {unsupported: [async]} - allSettled/is-function.js allSettled/iter-arg-is-false-reject.js {unsupported: [async]} allSettled/iter-arg-is-null-reject.js {unsupported: [async]} allSettled/iter-arg-is-number-reject.js {unsupported: [async]} @@ -1022,7 +1006,6 @@ built-ins/Promise 444/599 (74.12%) allSettled/iter-assigned-true-reject.js {unsupported: [async]} allSettled/iter-assigned-undefined-reject.js {unsupported: [async]} allSettled/iter-next-err-reject.js {unsupported: [async]} - allSettled/iter-next-val-err-no-close.js allSettled/iter-next-val-err-reject.js {unsupported: [async]} allSettled/iter-returns-false-reject.js {unsupported: [async]} allSettled/iter-returns-null-reject.js {unsupported: [async]} @@ -1031,31 +1014,11 @@ built-ins/Promise 444/599 (74.12%) allSettled/iter-returns-symbol-reject.js {unsupported: [async]} allSettled/iter-returns-true-reject.js {unsupported: [async]} allSettled/iter-returns-undefined-reject.js {unsupported: [async]} - allSettled/iter-step-err-no-close.js allSettled/iter-step-err-reject.js {unsupported: [async]} - allSettled/length.js - allSettled/name.js - allSettled/new-reject-function.js - allSettled/new-resolve-function.js - allSettled/prop-desc.js allSettled/reject-deferred.js {unsupported: [async]} - allSettled/reject-element-function-extensible.js - allSettled/reject-element-function-length.js - allSettled/reject-element-function-multiple-calls.js - allSettled/reject-element-function-name.js - allSettled/reject-element-function-nonconstructor.js - allSettled/reject-element-function-prototype.js allSettled/reject-ignored-deferred.js {unsupported: [async]} allSettled/reject-ignored-immed.js {unsupported: [async]} allSettled/reject-immed.js {unsupported: [async]} - allSettled/resolve-before-loop-exit.js - allSettled/resolve-before-loop-exit-from-same.js - allSettled/resolve-element-function-extensible.js - allSettled/resolve-element-function-length.js - allSettled/resolve-element-function-name.js - allSettled/resolve-element-function-nonconstructor.js - allSettled/resolve-element-function-prototype.js - allSettled/resolve-from-same-thenable.js allSettled/resolve-ignores-late-rejection.js {unsupported: [async]} allSettled/resolve-ignores-late-rejection-deferred.js {unsupported: [async]} allSettled/resolve-non-callable.js {unsupported: [async]} @@ -1074,7 +1037,6 @@ built-ins/Promise 444/599 (74.12%) allSettled/resolved-then-catch-finally.js {unsupported: [async]} allSettled/resolves-empty-array.js {unsupported: [async]} allSettled/resolves-to-array.js {unsupported: [async]} - allSettled/returns-promise.js allSettled/species-get-error.js {unsupported: [Symbol.species]} all/capability-resolve-throws-reject.js {unsupported: [async]} all/ctx-ctor.js {unsupported: [class]}