From 46c3b3d7342b7dd6f677b29ca009f70e40b7b97d Mon Sep 17 00:00:00 2001 From: Raul-Sebastian Mihaila Date: Sun, 25 Feb 2018 11:48:48 +0200 Subject: [PATCH 1/3] Fix Promise.prototype.finally to not incur extra ticks https://esdiscuss.org/topic/promise-finally --- spec.html | 97 +++++++++++++++++++------------------------------------ 1 file changed, 33 insertions(+), 64 deletions(-) diff --git a/spec.html b/spec.html index f7a9ca9172..f039dedc9e 100644 --- a/spec.html +++ b/spec.html @@ -38532,14 +38532,15 @@

PromiseReaction Records

-

CreateResolvingFunctions ( _promise_ )

+

CreateResolvingFunctions ( _promise_, _finallySourcePromise_ )

When CreateResolvingFunctions is performed with argument _promise_, the following steps are taken:

1. Let _alreadyResolved_ be a new Record { [[Value]]: *false* }. 1. Let _stepsResolve_ be the algorithm steps defined in Promise Resolve Functions (). - 1. Let _resolve_ be CreateBuiltinFunction(_stepsResolve_, « [[Promise]], [[AlreadyResolved]] »). + 1. Let _resolve_ be CreateBuiltinFunction(_stepsResolve_, « [[Promise]], [[AlreadyResolved]], [[FinallySourcePromise]] »). 1. Set _resolve_.[[Promise]] to _promise_. 1. Set _resolve_.[[AlreadyResolved]] to _alreadyResolved_. + 1. Set _resolve_.[[FinallySourcePromise]] to _finallySourcePromise_. 1. Let _stepsReject_ be the algorithm steps defined in Promise Reject Functions (). 1. Let _reject_ be CreateBuiltinFunction(_stepsReject_, « [[Promise]], [[AlreadyResolved]] »). 1. Set _reject_.[[Promise]] to _promise_. @@ -38566,10 +38567,11 @@

Promise Reject Functions

Promise Resolve Functions

-

A promise resolve function is an anonymous built-in function that has [[Promise]] and [[AlreadyResolved]] internal slots.

+

A promise resolve function is an anonymous built-in function that has [[Promise]], [[AlreadyResolved]] and [[FinallySourcePromise]] internal slots.

When a promise resolve function _F_ is called with argument _resolution_, the following steps are taken:

1. Assert: _F_ has a [[Promise]] internal slot whose value is an Object. + 1. Assert: _F_ has a [[FinallySourcePromise]] internal slot whose value is either a promise object with a [[PromiseState]] internal slot or *undefined*. 1. Let _promise_ be _F_.[[Promise]]. 1. Let _alreadyResolved_ be _F_.[[AlreadyResolved]]. 1. If _alreadyResolved_.[[Value]] is *true*, return *undefined*. @@ -38578,14 +38580,21 @@

Promise Resolve Functions

1. Let _selfResolutionError_ be a newly created *TypeError* object. 1. Return RejectPromise(_promise_, _selfResolutionError_). 1. If Type(_resolution_) is not Object, then - 1. Return FulfillPromise(_promise_, _resolution_). + 1. Let _finallySourcePromise_ be _F_.[[FinallySourcePromise]]. + 1. If _finallySourcePromise_ is *undefined* + 1. Return FulfillPromise(_promise_, _resolution_). + 1. Else + 1. If _finallySourcePromise_.[[PromiseState]] is "rejected" + 1. Return RejectPromise(_promise_, _finallySourcePromise_.[[PromiseResult]]). + 1. Else + 1. Return FulfillPromise(_promise_, _finallySourcePromise_.[[PromiseResult]]). 1. Let _then_ be Get(_resolution_, `"then"`). 1. If _then_ is an abrupt completion, then 1. Return RejectPromise(_promise_, _then_.[[Value]]). 1. Let _thenAction_ be _then_.[[Value]]. 1. If IsCallable(_thenAction_) is *false*, then 1. Return FulfillPromise(_promise_, _resolution_). - 1. Perform EnqueueJob(`"PromiseJobs"`, PromiseResolveThenableJob, « _promise_, _resolution_, _thenAction_ »). + 1. Perform EnqueueJob(`"PromiseJobs"`, PromiseResolveThenableJob, « _promise_, _resolution_, _thenAction_, _F_.[[FinallySourcePromise]] »). 1. Return *undefined*.

The `length` property of a promise resolve function is 1.

@@ -38609,15 +38618,17 @@

FulfillPromise ( _promise_, _value_ )

-

NewPromiseCapability ( _C_ )

-

The abstract operation NewPromiseCapability takes a constructor function, and attempts to use that constructor function in the fashion of the built-in `Promise` constructor to create a Promise object and extract its resolve and reject functions. The promise plus the resolve and reject functions are used to initialize a new PromiseCapability Record which is returned as the value of this abstract operation.

+

NewPromiseCapability ( _C_ [ , _finallySourcePromise_ ] )

+

The abstract operation NewPromiseCapability takes a constructor function, and attempts to use that constructor function in the fashion of the built-in `Promise` constructor to create a Promise object and extract its resolve and reject functions. The promise plus the resolve and reject functions are used to initialize a new PromiseCapability Record which is returned as the value of this abstract operation. NewPromiseCapability also takes an optional _finallySourcePromise_, which is either a promise object with a [[PromiseState]] internal slot or *undefined*. If _finallySourcePromise_ is a promise object, it is the promise object on which `Promise.prototype.finally` () was invoked, during which NewPromiseCapability was performed in order to create the resulted promise.

1. If IsConstructor(_C_) is *false*, throw a *TypeError* exception. 1. NOTE: _C_ is assumed to be a constructor function that supports the parameter conventions of the `Promise` constructor (see ). + 1. If _finallySourcePromise_ is not present, set _finallySourcePromise_ to *undefined*. 1. Let _promiseCapability_ be a new PromiseCapability { [[Promise]]: *undefined*, [[Resolve]]: *undefined*, [[Reject]]: *undefined* }. 1. Let _steps_ be the algorithm steps defined in . - 1. Let _executor_ be CreateBuiltinFunction(_steps_, « [[Capability]] »). + 1. Let _executor_ be CreateBuiltinFunction(_steps_, « [[Capability]] », « [[FinallySourcePromise]] »). 1. Set _executor_.[[Capability]] to _promiseCapability_. + 1. Set _executor_.[[FinallySourcePromise]] to _finallySourcePromise_. 1. Let _promise_ be ? Construct(_C_, « _executor_ »). 1. If IsCallable(_promiseCapability_.[[Resolve]]) is *false*, throw a *TypeError* exception. 1. If IsCallable(_promiseCapability_.[[Reject]]) is *false*, throw a *TypeError* exception. @@ -38631,10 +38642,11 @@

NewPromiseCapability ( _C_ )

GetCapabilitiesExecutor Functions

-

A GetCapabilitiesExecutor function is an anonymous built-in function that has a [[Capability]] internal slot.

+

A GetCapabilitiesExecutor function is an anonymous built-in function that has a [[Capability]] and a [[FinallySourcePromise]] internal slots.

When a GetCapabilitiesExecutor function _F_ is called with arguments _resolve_ and _reject_, the following steps are taken:

1. Assert: _F_ has a [[Capability]] internal slot whose value is a PromiseCapability Record. + 1. Assert: _F_ has a [[FinallySourcePromise]] internal slot whose value is either a promise object with a [[PromiseState]] internal slot or *undefined*. 1. Let _promiseCapability_ be _F_.[[Capability]]. 1. If _promiseCapability_.[[Resolve]] is not *undefined*, throw a *TypeError* exception. 1. If _promiseCapability_.[[Reject]] is not *undefined*, throw a *TypeError* exception. @@ -38737,10 +38749,10 @@

PromiseReactionJob ( _reaction_, _argument_ )

-

PromiseResolveThenableJob ( _promiseToResolve_, _thenable_, _then_ )

-

The job PromiseResolveThenableJob with parameters _promiseToResolve_, _thenable_, and _then_ performs the following steps:

+

PromiseResolveThenableJob ( _promiseToResolve_, _thenable_, _then_, _finallySourcePromise_ )

+

The job PromiseResolveThenableJob with parameters _promiseToResolve_, _thenable_, _then_, and _finallySourcePromise_ performs the following steps:

- 1. Let _resolvingFunctions_ be CreateResolvingFunctions(_promiseToResolve_). + 1. Let _resolvingFunctions_ be CreateResolvingFunctions(_promiseToResolve_, _finallySourcePromise_). 1. Let _thenCallResult_ be Call(_then_, _thenable_, « _resolvingFunctions_.[[Resolve]], _resolvingFunctions_.[[Reject]] »). 1. If _thenCallResult_ is an abrupt completion, then 1. Let _status_ be Call(_resolvingFunctions_.[[Reject]], *undefined*, « _thenCallResult_.[[Value]] »). @@ -38771,7 +38783,10 @@

Promise ( _executor_ )

1. Set _promise_.[[PromiseFulfillReactions]] to a new empty List. 1. Set _promise_.[[PromiseRejectReactions]] to a new empty List. 1. Set _promise_.[[PromiseIsHandled]] to *false*. - 1. Let _resolvingFunctions_ be CreateResolvingFunctions(_promise_). + 1. Let _finallySourcePromise_ be *undefined*. + 1. If _executor_ has a [[FinallySourcePromise]] internal slot, then + 1. Set _finallySourcePromise_ to _executor_.[[FinallySourcePromise]]. + 1. Let _resolvingFunctions_ be CreateResolvingFunctions(_promise_, _finallySourcePromise_). 1. Let _completion_ be Call(_executor_, *undefined*, « _resolvingFunctions_.[[Resolve]], _resolvingFunctions_.[[Reject]] »). 1. If _completion_ is an abrupt completion, then 1. Perform ? Call(_resolvingFunctions_.[[Reject]], *undefined*, « _completion_.[[Value]] »). @@ -39012,60 +39027,14 @@

Promise.prototype.constructor

Promise.prototype.finally ( _onFinally_ )

-

When the `finally` method is called with argument _onFinally_, the following steps are taken:

+

When the `finally` method is called with argument _onFinally_ and _onRejected_, the following steps are taken:

1. Let _promise_ be the *this* value. - 1. If Type(_promise_) is not Object, throw a *TypeError* exception. + 1. If IsPromise(_promise_) is *false*, throw a *TypeError* exception. 1. Let _C_ be ? SpeciesConstructor(_promise_, %Promise%). - 1. Assert: IsConstructor(_C_) is *true*. - 1. If IsCallable(_onFinally_) is *false*, then - 1. Let _thenFinally_ be _onFinally_. - 1. Let _catchFinally_ be _onFinally_. - 1. Else, - 1. Let _stepsThenFinally_ be the algorithm steps defined in . - 1. Let _thenFinally_ be CreateBuiltinFunction(_stepsThenFinally_, « [[Constructor]], [[OnFinally]] »). - 1. Set _thenFinally_.[[Constructor]] to _C_. - 1. Set _thenFinally_.[[OnFinally]] to _onFinally_. - 1. Let _stepsCatchFinally_ be the algorithm steps defined in . - 1. Let _catchFinally_ be CreateBuiltinFunction(_stepsCatchFinally_, « [[Constructor]], [[OnFinally]] »). - 1. Set _catchFinally_.[[Constructor]] to _C_. - 1. Set _catchFinally_.[[OnFinally]] to _onFinally_. - 1. Return ? Invoke(_promise_, `"then"`, « _thenFinally_, _catchFinally_ »). - - - -

Then Finally Functions

-

A Then Finally function is an anonymous built-in function that has a [[Constructor]] and an [[OnFinally]] internal slot. The value of the [[Constructor]] internal slot is a `Promise`-like constructor function object, and the value of the [[OnFinally]] internal slot is a function object.

-

When a Then Finally function _F_ is called with argument _value_, the following steps are taken:

- - 1. Let _onFinally_ be _F_.[[OnFinally]]. - 1. Assert: IsCallable(_onFinally_) is *true*. - 1. Let _result_ be ? Call(_onFinally_, *undefined*). - 1. Let _C_ be _F_.[[Constructor]]. - 1. Assert: IsConstructor(_C_) is *true*. - 1. Let _promise_ be ? PromiseResolve(_C_, _result_). - 1. Let _valueThunk_ be equivalent to a function that returns _value_. - 1. Return ? Invoke(_promise_, `"then"`, « _valueThunk_ »). - -

The `length` property of a Then Finally function is *1*.

-
- - -

Catch Finally Functions

-

A Catch Finally function is an anonymous built-in function that has a [[Constructor]] and an [[OnFinally]] internal slot. The value of the [[Constructor]] internal slot is a `Promise`-like constructor function object, and the value of the [[OnFinally]] internal slot is a function object.

-

When a Catch Finally function _F_ is called with argument _reason_, the following steps are taken:

- - 1. Let _onFinally_ be _F_.[[OnFinally]]. - 1. Assert: IsCallable(_onFinally_) is *true*. - 1. Let _result_ be ? Call(_onFinally_, *undefined*). - 1. Let _C_ be _F_.[[Constructor]]. - 1. Assert: IsConstructor(_C_) is *true*. - 1. Let _promise_ be ? PromiseResolve(_C_, _result_). - 1. Let _thrower_ be equivalent to a function that throws _reason_. - 1. Return ? Invoke(_promise_, `"then"`, « _thrower_ »). - -

The `length` property of a Catch Finally function is *1*.

-
+ 1. Let _resultCapability_ be ? NewPromiseCapability(_C_, _promise_). + 1. Return PerformPromiseThen(_promise_, _onFinally_, _onFinally_, _resultCapability_). +
From 1701879c1658d773b25fe82643951d33b6506d57 Mon Sep 17 00:00:00 2001 From: Raul-Sebastian Mihaila Date: Sun, 25 Feb 2018 11:56:55 +0200 Subject: [PATCH 2/3] Forgot to delete some words --- spec.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.html b/spec.html index f039dedc9e..b058eb2f93 100644 --- a/spec.html +++ b/spec.html @@ -39027,7 +39027,7 @@

Promise.prototype.constructor

Promise.prototype.finally ( _onFinally_ )

-

When the `finally` method is called with argument _onFinally_ and _onRejected_, the following steps are taken:

+

When the `finally` method is called with argument _onFinally_, the following steps are taken:

1. Let _promise_ be the *this* value. 1. If IsPromise(_promise_) is *false*, throw a *TypeError* exception. From 38fd8e82df12a4e828b6fe15cbafacea0bb17ee5 Mon Sep 17 00:00:00 2001 From: Raul-Sebastian Mihaila Date: Sun, 25 Feb 2018 12:34:30 +0200 Subject: [PATCH 3/3] Small improvement --- spec.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec.html b/spec.html index b058eb2f93..cbb81c88a3 100644 --- a/spec.html +++ b/spec.html @@ -38579,8 +38579,8 @@

Promise Resolve Functions

1. If SameValue(_resolution_, _promise_) is *true*, then 1. Let _selfResolutionError_ be a newly created *TypeError* object. 1. Return RejectPromise(_promise_, _selfResolutionError_). + 1. Let _finallySourcePromise_ be _F_.[[FinallySourcePromise]]. 1. If Type(_resolution_) is not Object, then - 1. Let _finallySourcePromise_ be _F_.[[FinallySourcePromise]]. 1. If _finallySourcePromise_ is *undefined* 1. Return FulfillPromise(_promise_, _resolution_). 1. Else @@ -38594,7 +38594,7 @@

Promise Resolve Functions

1. Let _thenAction_ be _then_.[[Value]]. 1. If IsCallable(_thenAction_) is *false*, then 1. Return FulfillPromise(_promise_, _resolution_). - 1. Perform EnqueueJob(`"PromiseJobs"`, PromiseResolveThenableJob, « _promise_, _resolution_, _thenAction_, _F_.[[FinallySourcePromise]] »). + 1. Perform EnqueueJob(`"PromiseJobs"`, PromiseResolveThenableJob, « _promise_, _resolution_, _thenAction_, _finallySourcePromise_ »). 1. Return *undefined*.

The `length` property of a promise resolve function is 1.