Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.
One, foreword
In the last article, according to the analysis and understanding of Promise, a simple version of Promise was realized, mainly involving the following contents:
- Promise implementation ideas;
- Promise A+ specification (simplified version);
- Promise simplified implementation and functional testing;
This article, translate and understand Promise A+ specification;
Note: Although there are many translation of Promise on the Internet, I still decided to translate it according to my own understanding.
2, 1) I Promise I’ll make A Promise
Liverpoolfc.tv: promisesaplus.com/
The original
An open Standard for Sound, Interoperable JavaScript Promises -- by Implementers, for implementers. 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. 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. 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. 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.Copy the code
translation
- An open, robust, and universal JavaScript Promise standard. Developed by developers for their reference.
- A Promise represents the end result of an asynchronous operation, and the primary way to interact with a Promise is through the then method, which registers two callback functions to receive the final value of a Promise or the reason why the Promise cannot be fulfilled.
- This specification specifies how the THEN method should behave. Promises that follow this Promise /A+ specification can use this standard as A reference to implement THE THEN method. This specification is therefore very stable. Although Promises/A+ organizations may occasionally modify this specification and make some backward compatible changes to address newly discovered boundary conditions, we will only make large-scale or incompatible changes after careful consideration, discussion, and testing.
- Promises/A+ Historically, the Promises/A+ specification made early Promises/A proposals clearer in terms of behavior. It expanded upon the original Promises/A proposals and omitted special cases and problematic parts of the original Promises/A proposals.
- Finally, the core Promises/A+ specification does not deal with how to create, implement, or reject Promises. Instead, it focuses on providing A universal then approach. Future work in supporting specifications may address these topics.
3, 2) Terminology
The original
1.1 "Promise" is an object or function with a then method whose behavior conforms to this specification. Is an object or function that defines a then method. a thenable, Or a promise). 1.4 "exception" is a value that is thrown using the throw statement. 1.5 "reason" is a value that indicates why a promise was rejected.Copy the code
translation
A Promise is an object or function that has a then method and its behavior complies with this specification. 1.2 Thenable is an object or function that defines (owns) the THEN method; 1.3 A value is any valid JavaScript value (including undefined, thenable, and promise); 1.4 An exception is a value thrown using a throw statement. Reason is a value that indicates the reason for the rejection of a promise.Copy the code
1. No, no, no, no.
3.1, The Promise States
A promise must be in one of three states: pending, depressing, or rejected. 2.1.1, When pending, A promise: 2.1.1.1, may transition to either the pity or rejected state. 2.1.2 When the pity, a promise: 2.1.2.1 Must not transition to any other state. 2.1.2.2must have a value, which must not change. 2.1.3 When Rejected, a promise: 2.1.3.1 Must not transition to any other state. 2.1.3.2 Must have a reason, which must not change. "Must not change" means immutable identity (i.e. ===), but does not imply deep immutability.Copy the code
- The current state of a Promise must be one of three:
- Pending state
- This is a big pity.
- (Rejected)
- 2.1.1, when a promise is in the wait state:
- 2.1.1.1, can be changed into a successful state or a failed state
- 2.1.2 When a Promise is in the success state:
- 2.1.2.1, cannot be changed to any other state
- 2.1.2.2, must have one value and cannot be changed
- 2.1.3 When a Promise is in the reject state:
- 2.1.3.1, cannot be changed to any other state
- 2.1.3.2, there must be a cause and it cannot be changed
By immutable, I mean identical, but not deeply immutable (the current reference space cannot be changed).
3.2, Thethen
Then approach (Method)
A promise must provide A then method to access its current or eventual value or reason. A promise's then method accepts A promise must provide a THEN method to access its current value, its final value, and the reason for its failure. Promise's then method accepts two arguments: Promise. Then (onFulfilled, onRejected) 2.2.1, Both onFulfilled and onRejected are optional arguments: This is a big pity. 2.2.1.1, If onFulfilled is not a function, it must be ignored. 2.2.1.2, This is a big pity. If onRejected is not a function, it must be ignored. 2.2.1, onRejected and onRejected are optional parameters: 2.2.1.1 if ondepressing is not a function, the ondepressing function must be ignored. 2.2.1.2, This is a big pity If onRejected is not a function, then the onRejected function must be ignored. 2.2.2.1, it must be called after promise is a big pity, with promise's value as its first argument. 2.2.2.2, This is a big pity; it must not be called before promise is fulfilled; 2.2.2.3, it must not be called more than once; 2.2.2, if ondepressing is a function: 2.2.2.1, ondepressing must be invoked when the promise state is successful, and the promise value is the first parameter. 2.2.2.2, ondepressing cannot be invoked before the promise state becomes a success state; 2.2.2.3 ondepressing can not be called many times; 2.2.3, If onRejected is a function: 2.2.3.1, onRejected must be called when the Promise state is failed, and the reason of the promise is the first parameter; 2.2.3.2, onRejected cannot be called before the Promise state fails; 2.2.3.3, onRejected cannot be called many times; 2.2.4. OnFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1]. OnFulfilled or onRejected is only allowed to run when the execution Context stack contains only the platform code. [3.1] Ondepressing and onRejected must be called as functions (i.e. with no this value). [3.2] Ondepressing and onRejected must be called as a function (ie this is undefined). [3.2] Then may be called multiple times on the same promise. 2.2.6.1, If/when promise is fulfilled, All the respective onFulfilled callbacks must execute in the order of their originating calls to then. 2.2.6.2, If/when promise is rejected, All terminals onRejected callbacks must execute in the order of their originating calls to then. 2.2.6, the same promise, 2.2.6.1 When the Promise is in a successful state, all ondepressing callback functions must be implemented in accordance with its registration order 2.2.6.2 When the Promise is in a failed state, All onRejected callback functions must be executed in the order in which they were registered. [3]. Promise2 = promise1. Then (onFulfilled, onRejected); 2.2.7.1, If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, X). 2.2.7.2, If either onFulfilled or onRejected throws an exception E, promise2 must be rejected with eas the reason. 2.2.7.3, If onFulfilled is not a function and promise1 is fulfilled, This is a big pity with the same value as promise1. 2.2.7.4, If onRejected is not a function and promise1 is rejected, Promise2 must be rejected with the same reason as promise1. 2.2.7, The then method must return a promise object [3.3]. Promise2 = promise1. 2.2.7.1 if onFulfilled or onRejected returns the value X, then perform the Promise resolution process [[Resolve]](promise2, x).2.2.7.2. If ondepressing or onRejected throws exception E, then promise2 becomes a failure state, and the reason is E. 2.2.7.3 if ondepressing is not a function and promise1 is successful, then promise2 will be successful and its value is the same as that of promise1. If onRejected is not a function and promise1 is in the failed state, promise2 is in the failed state for the same reason.Copy the code
3.3, The Promise Resolution Procedure
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, [[Resolve]](Resolve, x). [[Resolve]](Resolve, x). If X is a Thenable, it tries to make the Promise adopt the X state, assuming that X behaves at least somewhat like a Promise. Otherwise, Implementing a promise using the value of x. This treatment of Thenables promise Implementations to interoperate, Assimilate 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. To run [[Resolve]](promise, x), perform the following steps: To run [[Resolve]] (promise, x), perform the following steps: 2.3.1, If promise and x refer to the same object, reject promise with a TypeError as the reason. 2.3.1, If the promise and x point to the same value, reject the promise using TypeError as a reason. 2.3.2, If X is a promise, adopt its state [3.4]: 2.3.2.1, If X is pending, promise must remain pending until X is depressing or rejected. 2.3.2.2, Fulfill promise with the same value. 2.3.2.3, If/when x is rejected, reject promise with the same reason. 2.3.2, If x is rejected, reject promise with the same reason [3.4]: 2.3.2.1, if X is a pity state, the Promise must remain pending until X changes to a pity or rejected. 2.3.2.2, If X is a pity state, Fulfill promise uses x value. 2.3.2.3. If X is rejected, reject, THE promise uses x value as reason. Otherwise, if x is an object or function, 2.3.3.1, Let then be x.teng. [3.5] 2.3.3.2, Thrown exception E, reject promise with eas the reason If retrieving the property X. hen results in a thrown exception E, reject promise with eas the reason. If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where: 2.3.3.3.1, If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).2.3.3.3.2, If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).2.3.3.3.2, If/when rejectPromise is called with a reason R, reject promise with r.2.3.3.3.3, 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. 2.3.3.3.4, Throws an Exception e If calling then throws an Exception E, 2.3.3.3.4.1, If resolvePromise or rejectPromise have been called, ignore it. 2.3.3.3.4.2, Otherwise, reject promise with eas the reason. 2.3.3.4, If then is not a function, fulfill promise with x. 2.3.3, If x is an object or a function, then is assigned to x. teng. [3.5] 2.3.3.2 if an exception is thrown when x. Teng is used, this exception is used as the reason for promise reject. 2.3.3.3, If then is a function, call the then function with x as this, taking the first argument as resolvePromise and the second argument as rejectPromise: 2.3.3.3.1, if resolvePromise is called with y, execute [[Resolve]](promise, y).2.3.3.3.2, If the rejectPromise is invoked for reason r, reject the promise for reason R. 2.3.3.3.3, If both resolvePromise and rejectPromise are invoked, Or if the same argument is called several times, only the first call will take effect and subsequent calls will be ignored. 2.3.3.3.4.1, if resolvePromise or rejectPromise has been called, ignore it. 2.3.3.3.4.2, otherwise rejectPromise with eas reason. Fulfill Promise If x is not an object or function fulfill promise with x. 2.3.4 If x is not an object or function fulfill promise takes x as the value. 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] The promise resolution process is an abstract operation, It takes a promise and a value, which we express as [[Resolve]](Promise, x). If x has a then method and looks like a promise, the resolver attempts to make the promise accept the state of X. Otherwise it implements the promise with the value of x. This thenable feature makes Promise implementation more universal: as long as it exposes A THEN method that follows the Promise/A+ protocol; This also allows implementations that follow the Promise/A+ specification to coexist well with less formal but usable implementations. To run [[Resolve]](promise, x), follow these steps: 2.3.1 x equals Promise If promise and X refer to the same object, TypeError is used as evidence. 2.3.2 x is a Promise. Note 4 If X is in the wait state, the promise must remain in the wait state until x is executed or rejected. If x is in the execute state, execute the promise with the same value. Reject promise with the same grounds 2.3.3 x as an object or function If x is an object or function: Note 5 If an error e is thrown when taking the value of x. teng, then e is used as the basis for rejecting a promise. If then is a function, x is called as the scope of this. Pass two callback functions as arguments, the first called resolvePromise and the second called rejectPromise: If resolvePromise is called with the value y, run [[Resolve]](promise, y) if rejectPromise is called with the argument r, If both resolvePromise and rejectPromise are called, or if the same argument is invoked more than once, then the first call takes precedence and the remaining calls are ignored. If a resolvePromise or rejectPromise has already been called, ignore it. Otherwise, use e as the basis. 2.3.4 If x is not an object or function and x is not a promise, if a promise is resolved by an object in a loop's Thenable chain, The recursive nature of [[Resolve]](promise, thenable) causes it to be called again, which is infinite recursion. The algorithm does not require it, but encourages the agent to detect the presence of such recursion, and if so, reject the promise with an identifiable TypeError as a justification. Note 6Copy the code
5, 4.
3.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, 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. 3.2, That is, in strict mode this will be undefined inside of them; In sloppy mode, it will be the global Object. 3.3, 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. 3.4, 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. 3.5, 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.3.6, 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. 3.1 Platform code here refers to the engine, environment, and promise implementation code. In practice, ensure that the onFulfilled and onRejected methods are executed asynchronously and should be executed in a new execution stack after the event loop in which the THEN method is called. This event queue can be implemented using a "macro-task" mechanism or a "micro-task" mechanism. Because the promise implementation code is itself platform code, the code itself may already contain a task scheduling queue or "springboard" when processing the handler. Macrotask and Microtask are two categories of asynchronous tasks. When a task is suspended, the JS engine will divide all tasks into these two queues according to their categories. First, the JS engine will take out the first task from the MacroTask queue (also known as task queue), and then take out all tasks in the MicroTask queue to execute them in sequence. The MacroTask task is then fetched, and the cycle continues until both queues are complete. Macro-task: Script, setTimeout, setInterval, setImmediate, I/O, UI rendering Micro-task: Process. nextTick, Promises, Object.observe, Note 2: In strict mode, the value of this is undefined; In non-strict mode it is a global object. 3.3 Note 3 The code implementation allows promisE2 === PROMISe1 if all requirements are met. Each implementation should document whether and under what conditions it allows PROMISE2 === PROMISe1. 3.4 Note 4 In general, x is considered a true promise if it conforms to the current implementation. This rule allows those exceptions to accept Promises that meet known requirements. 3.5 Note 5 In this step, we first store a reference to x.teng, and then test and call the reference to avoid multiple access to the x.teng property. This precaution ensures that the property is consistent because its value can be changed during retrieval calls. 3.6 Note 6 The implementation should not impose a limit on the depth of the Thenable chain and assume that recursion beyond this limit is an infinite loop. Only true loop recursion should result in TypeError exceptions; If the Thenable is different across an infinite chain, recursion is always the correct behavior.Copy the code
To the extent possible under law, the Promises/A+ organization has waived all copyright and related or neighboring rights to Promises/A+ Promise Specification. This work is published from: United States. Promises/A+ waives all copyright and related or adjacent rights to the Promises/A+ Promise specification to the extent permitted by law. The work was published in the United States.Copy the code
Six, the end
This article, translated and understood the whole Promise A+ specification;
Next, we will continue to improve the function of the simplified Promise code based on the Promise A+ specification.
Next, the implementation of the Promise chain call;