From afd105b72dc8afe4b8dca237180ee2276c4ada3f Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 13 Aug 2013 22:23:39 -0400 Subject: [PATCH] Enforce a clean stack for `onFulfilled` and `onRejected`. Closes #139. See also discussions in #70, #84, and #100. --- README.md | 4 ++-- changelog.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 63da525..859b00e 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ promise.then(onFulfilled, onRejected) 1. it must be called after `promise` is rejected, with `promise`'s reason as its first argument. 1. it must not be called before `promise` is rejected. 1. it must not be called more than once. -1. `then` must return before `onFulfilled` or `onRejected` is called [[4.1](#notes)]. +1. `onFulfilled` or `onRejected` must not be called until the execution context stack contains only platform code. [[4.1](#notes)]. 1. `onFulfilled` and `onRejected` must be called as functions (i.e. with no `this` value). [[4.2](#notes)] 1. `then` may be called multiple times on the same promise. 1. If/when `promise` is fulfilled, all respective `onFulfilled` callbacks must execute in the order of their originating calls to `then`. @@ -102,7 +102,7 @@ If a promise is resolved with a thenable that participates in a circular thenabl ## Notes -1. In practical terms, an implementation must use a mechanism such as `setTimeout`, `setImmediate`, or `process.nextTick` to ensure that `onFulfilled` and `onRejected` are not invoked in the same turn of the event loop as the call to `then` to which they are passed. +1. Here "platform code" means engine, environment, and promise implementation code. In practice, this requirement ensures that `onFulfilled` and `onRejected` execute asynchronously, after the event loop turn in which `then` is called, and with a fresh stack. This can be implemented with either a "macro-turn" mechanism such as `setTimeout` or `setImmediate`, or with a "micro-turn" mechanism such as `Object.observe` or `process.nextTick`. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or "trampoline" in which the handlers are called. 1. That is, in strict mode `this` will be `undefined` inside of them; in sloppy mode, it will be the global object. diff --git a/changelog.md b/changelog.md index 2941adc..d588c32 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ These changes help clarify and improve the specification, but should not affect These changes impose new requirements on implementations, either to specify a previously-undefined behavior, or to fix something incorrect that the spec allowed in version 1.0. - Specified that `onFulfilled` and `onRejected` must be called as functions, with no `this` value. +- Changed the way in which asynchronicity was mandated for `onFulfilled` and `onRejected`, to enforce the important invariant that the stack be clear. In particular, the new wording prevents fulfilling or rejecting a promise from ever synchronously calling the handlers. - Prohibited implementations from calling `onFulfilled` or `onRejected` before the corresponding promise was respectively fulfilled or rejected. - Specified the Promise Resolution Procedure, instead of leaving the mechanism for adopting a thenable's state unspecified. - The recursive nature of the now-specified procedure improves upon the naïve non-recursive suggestion given in version 1.0.