Add Promise.prototype.finally().
This commit is contained in:
parent
b8c8d932f2
commit
adaffdd732
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -2102,6 +2102,21 @@ intrinsic_ModuleNamespaceExports(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
|
||||
RootedObject constructor(cx, &args[0].toObject());
|
||||
JSObject* promise = js::PromiseResolve(cx, constructor, args[1]);
|
||||
if (!promise)
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*promise);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The self-hosting global isn't initialized with the normal set of builtins.
|
||||
// Instead, individual C++-implemented functions that're required by
|
||||
// self-hosted code are defined as global functions. Accessing these
|
||||
|
@ -2498,6 +2513,10 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
|
||||
JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
|
||||
|
||||
JS_FN("IsPromiseObject", intrinsic_IsInstanceOfBuiltin<PromiseObject>, 1, 0),
|
||||
JS_FN("CallPromiseMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<PromiseObject>>, 2, 0),
|
||||
JS_FN("PromiseResolve", intrinsic_PromiseResolve, 2, 0),
|
||||
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
@ -243,7 +243,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
|||
"$`", "$'", Symbol.species])
|
||||
|
||||
gPrototypeProperties['Promise'] =
|
||||
["constructor", "catch", "then", Symbol.toStringTag];
|
||||
["constructor", "catch", "then", "finally", Symbol.toStringTag];
|
||||
gConstructorProperties['Promise'] =
|
||||
constructorProps(["resolve", "reject", "all", "race", Symbol.species]);
|
||||
|
||||
|
|
Loading…
Reference in New Issue