summaryrefslogtreecommitdiff
path: root/js/src/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin')
-rw-r--r--js/src/builtin/Promise.cpp8
-rw-r--r--js/src/builtin/Promise.h8
-rw-r--r--js/src/builtin/Promise.js69
3 files changed, 85 insertions, 0 deletions
diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp
index ec7845e89d..1d068f8c64 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 c76dc358c7..6a6453e465 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 704cbab0be..91a1e1f562 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);
+}