序論
`~promise$は、非同期的~演算の最終的な結果を表現する。 ~promiseとのやりとりは、主に,その `then^es ~methodを通して~~行われる — それは、[ ~promiseの最終的な値を受取る~callback ], または/および[ ~promiseを充足できなかったときに その`事由$を受取る~callback ]を登録する。 ◎ A promise represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its then method, which registers callbacks to receive either a promise’s eventual value or the reason why the promise cannot be fulfilled.
この仕様は、 `then^es ~methodの挙動の詳細を与える — それは、[ すべての[ Promises/A+ に適合する~promise実装 ]が,それを供することに依存できる ]ような,相互運用可能な基盤を供する。 そのようなわけで、この仕様は ごく安定的と見なされるべきである。 新たに際どい事例が発見されれば,それに取組むため、この仕様は Promises/A+ organization により[ 小さな, かつ後方-互換な変更点 ]で改訂されることもあり得るが、[ 大きな, または後方-互換でない変更点 ]が統合されるのは、[ 注意深く考慮され, 議論が積み重ねられ, ~testされた ]後に限られることになる。 ◎ This specification details the behavior of the then method, providing an interoperable base which all Promises/A+ conformant promise implementations can be depended on to provide. As such, the specification should be considered very stable. Although the Promises/A+ organization may occasionally revise this specification with minor backward-compatible changes to address newly-discovered corner cases, we will integrate large or backward-incompatible changes only after careful consideration, discussion, and testing.
歴史的に, Promises/A+ は、早期の Promises/A 提案 の挙動上の各~条項を明確化し、[ 事実的標準 とされている挙動を受持つ ]ために それを拡張し,また[ 指定中にある/問題になり得る ]部分は切落としてきた。 ◎ Historically, Promises/A+ clarifies the behavioral clauses of the earlier Promises/A proposal, extending it to cover de facto behaviors and omitting parts that are underspecified or problematic.
~~最終的に,中核の Promises/A+ 仕様は、~promiseをどう 作成する/`充足する$/`却下する$ かについては取り組まず、代わりに,相互運用可能な `then^es ~methodを供することに集中する。 姉妹~仕様における将来の成果が,これらの主題に触れることになるであろう。 ◎ Finally, the core Promises/A+ specification does not deal with how to create, fulfill, or reject promises, choosing instead to focus on providing an interoperable then method. Future work in companion specifications may touch on these subjects.
【この訳に特有な表記規約】
◎表記記号1. 各種用語
- `~promise@
- `then^es ~methodを備える ~object/~function であって,その挙動がこの仕様に適合するもの。 ◎ “promise” is an object or function with a then method whose behavior conforms to this specification.
- `~thenable@
- `then^es ~methodを定義するような, ~object/~function 。 ◎ “thenable” is an object or function that defines a then method.
- `値@
- 任意の合法な~JS値( `undefined^es, `~thenable$, `~promise$も含む)。 ◎ “value” is any legal JavaScript value (including undefined, a thenable, or a promise).
- `例外@
- `throw^c 文を利用して投出される`値$。 ◎ “exception” is a value that is thrown using the throw statement.
- `事由@
- `~promise$がなぜ`却下され$たかを指示する`値$。 ◎ “reason” is a value that indicates why a promise was rejected.
2. 要件
2.1. ~promiseの各種~状態
`~promise$は、[ `処理待ち@ / `充足-済み@ / `却下-済み@ ]のいずれかの状態にあることが要求される。 ~promiseは: ◎ A promise must be in one of three states: pending, fulfilled, or rejected.
-
`処理待ち$にあるときは: ◎ When pending, a promise:
- [ `充足-済み$, `却下-済み$ ]いずれかの状態に遷移し得る。 ◎ may transition to either the fulfilled or rejected state.
-
`充足-済み$にあるときは: ◎ When fulfilled, a promise:
- 他の状態に遷移してはナラナイ。 ◎ must not transition to any other state.
- `値$を持たなければナラナイ。 この値は変化してはナラナイ。 ◎ must have a value, which must not change.
-
`却下-済み$にあるときは: ◎ When rejected, a promise:
- 他の状態に遷移してはナラナイ。 ◎ must not transition to any other state.
- `事由$を持たなければナラナイ。 この事由は変化してはナラナイ。 ◎ must have a reason, which must not change.
ここで、
“変化してはナラナイ”
とは、同一性について変異-不能である(すなわち, ===
)を意味する。
深い変異-不能性を含意するものではない
【 ~objectであれば その~memberの同一性が保たれる必要はない 】
。
◎
Here, “must not change” means immutable identity (i.e. ===), but does not imply deep immutability.
【 定義~補足: 】
- `充足する@( fulfill )
- “`値$ %v で`~promise$ %promise を充足する” という句は、 %promise を`充足-済み$状態に遷移させると同時に, %promise の`値$を %v にすることを意味する。
- `却下する@( reject )
- “`事由$ %r で`~promise$ %promise を却下する” という句は、 %promise を`却下-済み$状態に遷移させると同時に, %promise の`事由$を %r にすることを意味する。
2.2. `then^es ~method
`~promise$は、[ その[ 現在の/最終的な ][ `値$, あるいは`事由$ ]に~accessするための, `then^es ~method ]を供さなければナラナイ。 ◎ A promise must provide a then method to access its current or eventual value or reason.
`~promise$ %promise の `then^es ~methodは、二個の引数を受容する: ◎ A promise’s then method accepts two arguments:
%promise.then(%onFulfilled, %onRejected)
-
%onFulfilled, %onRejected 両~引数とも省略可能である: ◎ Both onFulfilled and onRejected are optional arguments:
- ~functionでない %onFulfilled は無視されなければナラナイ。 ◎ If onFulfilled is not a function, it must be ignored.
- ~functionでない %onRejected は無視されなければナラナイ。 ◎ If onRejected is not a function, it must be ignored.
-
%onFulfilled は、それが~functionであるならば: ◎ If onFulfilled is a function:
- %promise が`充足され$た後に,その 1 個目の引数に %promise の`値$を渡して ~callされなければナラナイ。 ◎ it must be called after promise is fulfilled, with promise’s value as its first argument.
- %promise が`充足され$る前に~callされてはナラナイ。 ◎ it must not be called before promise is fulfilled.
- 複数回~callされてはナラナイ。 ◎ it must not be called more than once.
-
%onRejected は、それが~functionであるならば: ◎ If onRejected is a function,
- %promise が`却下され$た後に、その 1 個目の引数に %promise の`事由$を渡して ~callされなければナラナイ。 ◎ it must be called after promise is rejected, with promise’s reason as its first argument.
- %promise が`却下され$る前に~callされてはナラナイ。 ◎ it must not be called before promise is rejected.
- 複数回~callされてはナラナイ。 ◎ it must not be called more than once.
- %onFulfilled / %onRejected は、[ 実行~文脈 ~stackが包含する~codeが,~platform~codeのみになる ]まで、~callされてはナラナイ。 [注 3.1] ◎ onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
- %onFulfilled / %onRejected は、 ~functionとして(すなわち, `this^es 値を伴わずに)~callされなければナラナイ。 [注 3.2] ◎ onFulfilled and onRejected must be called as functions (i.e. with no this value). [3.2]
-
同じ`~promise$上で, `then^es が複数回~callされることもあり得る — その際には: ◎ then may be called multiple times on the same promise.
- %promise が[ `充足され$たとき/`充足-済み$にあるとき ]は ⇒ 渡された一連の %onFulfilled ~callbackは、それぞれの出自の `then^es が~callされた順序で実行されなければナラナイ。 ◎ If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
- %promise が[ `却下され$たとき/`却下-済み$にあるとき ]は ⇒ 渡された一連の %onRejected ~callbackは、それぞれの出自の `then^es が~callされた順序で実行されなければナラナイ。 ◎ If/when promise is rejected, all respective onRejected callbacks must execute in the order of their originating calls to then.
-
`then^es は`~promise$を返すモノトスル。 [注 3.3] ◎ then must return a promise [3.3].
%promise2 = %promise1.then(%onFulfilled, %onRejected);
-
%onFulfilled / %onRejected が`値$ %x を返したならば
⇒
~promiseの解決~手続-:
[[Resolve]](%promise2, %x)
を走らす。 ◎ If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x). - %onFulfilled / %onRejected が `例外$ %e を投出したならば ⇒ %promise2 は,`事由$ %e で`却下され$なければナラナイ。 ◎ If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
- %onFulfilled は~functionでない, かつ %promise1 が`充足され$たならば ⇒ %promise2 は, %promise1 の値と同じ値で`充足され$なければナラナイ。 ◎ If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
- %onRejected は~functionでない, かつ %promise1 が`却下され$たならば ⇒ %promise2 は, %promise1 の`事由$と同じ値で`却下され$なければナラナイ。 ◎ If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.
-
%onFulfilled / %onRejected が`値$ %x を返したならば
⇒
~promiseの解決~手続-:
2.3 ~promiseの解決~手続-
~promiseの解決~手続-
は、`~promise$, および`値$を入力にとる抽象-演算であり、
[[Resolve]](%promise, %x)
と表記される。
%x が`~thenable$であるならば、それは
%promise に %x の状態を取入れさせようと試みる
— %x が,少なくとも~promiseに似た何かであるかのように挙動する前提の下で。
~~他の場合、それは,値 %x で %promise を`充足する$。
◎
The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x). If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the value x.
この~thenableの扱いにより、~promise実装は,[ ~thenableが Promises/A+ に準拠する `then^es ~methodを公開する ]限りにおいて,相互運用可能になる。 それはまた, Promises/A+ 実装が、適合tでない実装を,適度な `then^es ~methodで “消化-” できるようにする。 ◎ This treatment of thenables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliant then method. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonable then methods.
[[Resolve]](%promise, %x)
を走らすときは、次の手続きを遂行する:
◎
To run [[Resolve]](promise, x), perform the following steps:
- %promise と %x が同じ~objectを指すならば ⇒ `事由$ `TypeError^es で %promise を`却下する$ ◎ If promise and x refer to the same object, reject promise with a TypeError as the reason.
-
~IF %x は`~promise$である ⇒ その状態を取入れる [注 3.4] — すなわち, %x の状態に応じて: ◎ If x is a promise, adopt its state [3.4]:
- `処理待ち$
- %promise は、[ %x が`充足され$る/`却下され$る ]まで,`処理待ち$であり続けなければナラナイ — %x の状態が遷移したときは、遷移~~後の状態に応じて,下の対応する段を走らすことになる。 ◎ If x is pending, promise must remain pending until x is fulfilled or rejected.
- `充足-済み$
- %x の`値$で %promise を`充足する$ ◎ If/when x is fulfilled, fulfill promise with the same value.
- `却下-済み$
- %x の`事由$で %promise を`却下する$ ◎ If/when x is rejected, reject promise with the same reason.
-
~ELIF %x は~object/~functionである: ◎ Otherwise, if x is an object or function,
-
%then ~LET
%x.`then^es
[注 3.5] ◎ Let then be x.then. [3.5] - ~IF 前段で `then^es を~~取得するときに、`例外$ %e が投出された ⇒ `事由$ %e で %promise を`却下する$ ◎ If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
-
~IF %then は~functionである: ◎ ↓
-
[ `this^es 値 ~SET %x ]の下で,次の二つの引数を渡して %then を~callする: ◎ If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where:
-
1 個目の引数 %resolvePromise は、`値$ %y を伴って~callされたときに,
[[Resolve]](%promise, %y)
を走らす~functionである。 ◎ If/when resolvePromise is called with a value y, run [[Resolve]](promise, y). - 2 個目の引数 %rejectPromise は、`事由$ %r を伴って~callされたときに, %r で %promise を`却下する$~functionである。 ◎ If/when rejectPromise is called with a reason r, reject promise with r.
- ただし、[ %resolvePromise, %rejectPromise の両者, または いずれか ]が(合計で)複数回 ~callされたときは、初回の~callが~~優先され、以降の~callは無視される【何もしない】。 ◎ If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
-
1 個目の引数 %resolvePromise は、`値$ %y を伴って~callされたときに,
-
~IF %then の~callにより,`例外$ %e が投出された: ◎ If calling then throws an exception e,
- ~IF %resolvePromise, %rejectPromise いずれかは すでに~callされている ⇒ %e を無視する ◎ If resolvePromise or rejectPromise have been called, ignore it.
- ~ELSE ⇒ `事由$ %e で %promise を`却下する$ ◎ Otherwise, reject promise with e as the reason.
-
- ~ELSE ⇒ %x で %promise を`充足する$ ◎ If then is not a function, fulfill promise with x.
-
%then ~LET
- ~ELSE ⇒ %x で %promise を`充足する$ ◎ If x is not an object or function, fulfill promise with x.
`~promise$が,[[[
[[Resolve]](%promise, thenable)
の再帰的な資質により,最終的に
[[Resolve]](%promise, thenable)
が再び~callされることになる
]ような,循環的な`~thenable$の連鎖
]に関与するような`~thenable$
]で解決されたならば、上の~algoをナゾることは,無限~再帰をもたらすことになる。
実装には、要求されてはいないが,そのような再帰を検出して,
`事由$ `TypeError^es で %promise を`却下する$ことが奨励される。
[注 3.6]
◎
If a promise is resolved with a thenable that participates in a circular thenable chain, such that the recursive nature of [[Resolve]](promise, thenable) eventually causes [[Resolve]](promise, thenable) to be called again, following the above algorithm will lead to infinite recursion. Implementations are encouraged, but not required, to detect such recursion and reject promise with an informative TypeError as the reason. [3.6]
3. 注記
- ここでの “~platform~code” は、[ ~engine/環境/~promise ]の実装~codeを意味する。 実施においては、この要件により,[ %onFulfilled / %onRejected が,[ `then^es が~callされた~event~loopの~turn ]の後に,新鮮な~stackの下で,非同期的に実行される ]ことが確保される。 これは、 `setTimeout$c や `setImmediate$c などによる “~macro-task” , あるいは `MutationObserver$c や `process.nextTick$c などによる “~micro-task” の仕組みにより,実装し得る。 ~promise実装は,~platform~codeと見なされるので、それ自身も[ 中で~handlerが~callされるような,[ ~taskを~scheduleする~queueや “~trampoline” 【trampoline】 ]]を包含することもある。 ◎ 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-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver 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.
- すなわち `this^es は、~strict~modeの下では,それらの内側では `undefined^es になり、~sloppy~mode【非~strict~mode】の下では,大域~objectになる。 ◎ That is, in strict mode this will be undefined inside of them; in sloppy mode, it will be the global object.
-
実装は、
%promise2 === %promise1
を許容してもヨイ — 実装がすべての要件を満たす限りにおいて。 各~実装は、どの条件の下で%promise2 === %promise1
になり得るかについて文書化するべきである。 ◎ Implementations may allow promise2 === promise1, provided the implementation meets all requirements. Each implementation should document whether it can produce promise2 === promise1 and under what conditions. - 一般に、 %x が真の`~promise$であることは、現在の実装から来ているときにのみ,知り得る【?】。 この条項により、実装は,自身に特有の手段を利用して[ 適合tが既知である~promise ]の状態を,取入れることが~~可能になる。 ◎ Generally, it will only be known that x is a true promise if it comes from the current implementation. This clause allows the use of implementation-specific means to adopt the state of known-conformant promises.
-
この,[
まず
%x.`then^es
への参照を格納した上で,その参照を~testしてから,その参照を~callする ]手続-により、[ 複数回にわたる%x.`then^es
~propertyへの~access ]は避けられる。 そのような用心は、[ 各~~取得の合間に値が変化し得るような,~accessor~propertyの一面 ]における一貫性を確保するために,重要になる。 ◎ This procedure of first storing a reference to x.then, then testing that reference, and then calling that reference, avoids multiple accesses to the x.then property. Such precautions are important for ensuring consistency in the face of an accessor property, whose value could change between retrievals. - 実装は、`~thenable$が成す連鎖の深さに恣意的な上限を設定するべきでない — 再帰は,その恣意的な上限を超えて無限になるものと見做すべきである。 `TypeError^es をもたらすのは、真の循環に限られるべきである — 別個な~thenableからなる無限~連鎖に遭遇したときの無限再帰は、正しい挙動である。 ◎ Implementations should not set arbitrary limits on the depth of thenable chains, and assume that beyond that arbitrary limit the recursion will be infinite. Only true cycles should lead to a TypeError; if an infinite chain of distinct thenables is encountered, recursing forever is the correct behavior.