diff options
Diffstat (limited to 'js/src/builtin')
-rw-r--r-- | js/src/builtin/Promise.cpp | 8 | ||||
-rw-r--r-- | js/src/builtin/Promise.h | 8 | ||||
-rw-r--r-- | js/src/builtin/Promise.js | 69 |
3 files changed, 85 insertions, 0 deletions
diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index ec7845e89..1d068f8c6 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -2006,6 +2006,13 @@ CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue ar return promise; } +MOZ_MUST_USE JSObject* +js::PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value) +{ + RootedValue C(cx, ObjectValue(*constructor)); + return CommonStaticResolveRejectImpl(cx, C, value, ResolveMode); +} + /** * ES2016, 25.4.4.4, Promise.reject. */ @@ -2739,6 +2746,7 @@ CreatePromisePrototype(JSContext* cx, JSProtoKey key) static const JSFunctionSpec promise_methods[] = { JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0), JS_FN("then", Promise_then, 2, 0), + JS_SELF_HOSTED_FN("finally", "Promise_finally", 1, 0), JS_FS_END }; diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index c76dc358c..6a6453e46 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -128,6 +128,14 @@ OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled, HandleValue onRejected, MutableHandleObject dependent, bool createDependent); +/** + * PromiseResolve ( C, x ) + * + * The abstract operation PromiseResolve, given a constructor and a value, + * returns a new promise resolved with that value. + */ +MOZ_MUST_USE JSObject* +PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value); MOZ_MUST_USE PromiseObject* CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal); diff --git a/js/src/builtin/Promise.js b/js/src/builtin/Promise.js index 704cbab0b..91a1e1f56 100644 --- a/js/src/builtin/Promise.js +++ b/js/src/builtin/Promise.js @@ -14,3 +14,72 @@ function Promise_catch(onRejected) { // Steps 1-2. return callContentFunction(this.then, this, undefined, onRejected); } + +// Promise.prototype.finally(onFinally) +// See https://tc39.es/proposal-promise-finally/ +function Promise_finally(onFinally) { + // Step 1. + var promise = this; + + // Step 2. + if (!IsObject(promise)) + ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "Promise", "finally", "value"); + + // Step 3. + var C = SpeciesConstructor(promise, GetBuiltinConstructor("Promise")); + + // Step 4. + assert(IsConstructor(C), "SpeciesConstructor returns a constructor function"); + + // Steps 5-6. + var thenFinally, catchFinally; + if (!IsCallable(onFinally)) { + thenFinally = onFinally; + catchFinally = onFinally; + } else { + // ThenFinally Function. + // The parentheses prevent the inferring of a function name. + (thenFinally) = function(value) { + // Steps 1-2 (implicit). + + // Step 3. + var result = onFinally(); + + // Steps 4-5 (implicit). + + // Step 6. + var promise = PromiseResolve(C, result); + + // Step 7. + // FIXME: spec issue - "be equivalent to a function that" is not a defined spec term. + // https://github.com/tc39/ecma262/issues/933 + + // Step 8. + return callContentFunction(promise.then, promise, function() { return value; }); + }; + + // CatchFinally Function. + // The parentheses prevent the inferring of a function name. + (catchFinally) = function(reason) { + // Steps 1-2 (implicit). + + // Step 3. + var result = onFinally(); + + // Steps 4-5 (implicit). + + // Step 6. + var promise = PromiseResolve(C, result); + + // Step 7. + // FIXME: spec issue - "be equivalent to a function that" is not a defined spec term. + // https://github.com/tc39/ecma262/issues/933 + + // Step 8. + return callContentFunction(promise.then, promise, function() { throw reason; }); + }; + } + + // Step 7. + return callContentFunction(promise.then, promise, thenFinally, catchFinally); +} |