Some key problems of promise
-
How to change the state of promise?
(1) resolve(value): if it is currently pending, it will become resolved
(2) reject(reason): if it is currently pending, it will become rejected
(3) Throw an exception: if it is currently pending, it will become rejected -
If a promise specifies multiple success / failure callback functions, will they be called?
Called when promise changes to the corresponding state
-
Who changes promise state and specifies callback function first and then?
(1) It is possible to specify the callback first and then change the state, but you can also change the state first and then specify the callback
(2) How to change the status before specifying callback?
① Directly call resolve()/reject() in the executor
② Call then() after a longer delay
(3) When can I get the data?
① If you specify the callback first, when the state changes, the callback function will be called to get the data
② If the state of the is changed first, when the callback is specified, the callback function will be called to get the data -
promise. What determines the result status of the new promise returned by then()?
(1) Simple expression: determined by the result of the callback function specified by then()
(2) Detailed expression:
① If an exception is thrown, the new promise becomes rejected and reason is the exception thrown
② If any value other than promise is returned, the new promise becomes resolved and value is the returned value
③ If another new promise is returned, the result of this promise will become the result of the new promise -
How does promise connect multiple operation tasks in series?
(1) promise's then() returns a new promise, which can be opened as a chain call to then()
(2) Connect multiple synchronous / asynchronous tasks in series through the chain call of then -
promise abnormal transmission?
(1) When using promise's then chain call, you can specify the failed callback at the end,
(2) If any previous operation is abnormal, it will be transferred to the last failed callback for processing -
How to interrupt promise chain?
(1) When the then chain call of promise is used, it is interrupted in the middle and the subsequent callback function is no longer called
(2) Method: return a promise object in pending status in the callback function -
Why should then and other methods be defined on the prototype?
(1) When the method is defined on this inside the constructor, when instantiating multiple objects, the method will also be copied (that is, each instantiated object has a method). In this way, when the constructor needs to instantiate many objects, the method of each instantiated object will occupy a certain amount of memory, which will lead to too much memory overhead
(2) For methods defined by prototype, when instantiating objects, only a pointer to the method is copied in each object, so in fact, there is only one method in the memory occupied
(3) Therefore, comparing the two, using prototype to define methods can save a lot of memory overhead. However, in the constructor, the variables defined include private variables (i.e. variables defined through var) and public variables (i.e. variables defined through this). Because private variables cannot be accessed by the outside world, we need to have a way to access private variables from the outside world, and the method defined through this in the constructor can effectively access private variables
-
Why are callbacks executed asynchronously in Promise then?
If callbacks (such as those in then) can be synchronous or asynchronous, the execution order becomes uncertain and the consistency of program logic cannot be guaranteed, which is similar to the race condition in multithreading. To avoid this uncertainty, then's callback is always executed as the next Job in the Job Queue (asynchronously).
For example:
promise.then(function(){ if (trueOrFalse) { // Synchronous execution foo(); } else { // Asynchronous execution (e.g. using third-party libraries) setTimeout(function(){ foo(); }) } }); bar();
-
If the promise then callback is executed synchronously, who will execute the foo () and bar () functions first? The answer is that if trueOrFalse is true, foo() will execute first and bar() will execute later; Otherwise, bar () will be executed first and foo () will be executed later. In most cases, you can't expect the value of trueOrFalse, which means that you can't determine the real execution order of this code, which may lead to some unexpected bug s.
-
If the promise then callback is executed asynchronously, who will execute the foo() and bar() functions first? The answer is clear at a glance. bar() executes first and foo() executes later.
Therefore, in order to ensure the consistency of code execution order, the then callback must be asynchronous.
Code implementation of promise
//Promise is a constructor //It is found that [[PromiseState]] and [[PromiseResult]] have double brackets when printing the native Promise, indicating that these two properties are built-in and cannot be modified externally //The contents of the executor function are executed synchronously function Promise(executor) { //Status value this.PromiseState = 'pending'; //Attribute value this.PromiseResult = null; //An array of objects containing onResolved and onRejected callback functions to be called this.callbacks = []; const self = this; // this in function points to window function resolve(data) { if(self.PromiseState !== 'pending') return; self.PromiseState = 'fulfilled'; self.PromiseResult = data; //Asynchronously call all pending onResolved successful callback functions if(self.callbacks.length > 0) { setTimeout(() => { self.callbacks.forEach(item => { item.onResolved(); }); }) } } function reject(data) { if(self.PromiseState !== 'pending') return; self.PromiseState = 'fulfilled'; self.PromiseResult = data; //Asynchronously call all the onRejected successful callback functions to be processed if(self.callbacks.length > 0) { setTimeout(() => { self.callbacks.forEach(item => { item.onRejected(); }); }) } } try { //Synchronous call to executor function executor(resolve, reject); }catch(e) { reject(e); //The exception is a direct failure } } Promise.prototype.then = function(onResolved, onRejected) { const self = this; // Handling exception penetration //If there is an exception in the rejected function, or if there is no rejected in the rejected function, the exception will be handled all the time, but it will be handed over to the rejected function if(typeof onRejected !== 'function') { onRejected = reason => { throw reason; } } if(typeof onResolved !== 'function') { onResolved = value => value; } return new Promise((resolve, reject) => { function callback(type) { try { let result = type(self.PromiseResult); if(result instanceof Promise) { // Returns a new promise result.then(v => { resolve(v); }, r => { reject(r); }) }else { resolve(result); } }catch(e) { reject(e); } } if(this.PromiseState === 'fulfilled') { setTimeout(() => { callback(onResolved); }) } if(this.PromiseState === 'rejected') { setTimeout(() => { callback(onRejected); }) } if(this.PromiseState === 'pending') { //Save onResolved and onRejected this.callbacks.push({ onResolved: function() { callback(onResolved); }, onRejected: function() { callback(onRejected); } }) } }) } Promise.prototype.catch = function(onRejected) { return this.then(undefined, onRejected); } //Returns a successful promise object Promise.resolve = function(value) { return new Promise((resolve, reject) => { if(value instanceof Promise) { value.then(v => { resolve(v); }, r => { reject(r); }) }else { resolve(value); } }) } //Returns a failed promise object Promise.reject = function(reason) { return new Promise((resolve, reject) => { reject(reason); }) } // Return a new promise. It will succeed only if all promises are successful. As long as one fails, it will fail directly Promise.all = function(promises) { return new Promise((resolve, reject) => { let count = 0; let arr = []; for(let i=0; i<promises.length; i++) { promises[i].then(v => { count++; arr[i] = v; //Success is returned only if all promise s are successful if(count === promises.length) { resolve(arr); } }, r => { // As long as there is one failure, it returns failure reject(r); }) } }) } // Returns a new promise. The result state of the first completed promise is the final result state Promise.race = function(promises) { return new Promise((resolve, reject) => { for(let i=0; i<promises.length; i++) { promises[i].then(v => { resolve(v); }, r => { reject(r); }) } }) }
-