Promise
1. What is Promise?
- Abstract Representation: Promises are a new solution to asynchronous programming in JS in the form of nested callback functions before promises are proposed
- The Promise object is used to indicate the final state (completion or failure) of an asynchronous operation and the result value of that asynchronous operation. A Promise is an object that represents the final completion or failure of an asynchronous operation. C. A Promise object is a proxy object (proxying a value) whose proxied value may not be known at the time the Promise object is created. It allows you to bind handlers for success and failure of asynchronous operations. This allows asynchronous methods to return values as synchronous methods do, but instead of immediately returning final execution results, a Promise object that represents future results
2. Why Promise?
1). The way to specify the callback function is more flexible: a. Old: the callback function must be specified before starting the asynchronous task, otherwise it cannot be listened; B. Promise: Start asynchronous task => return promie object => Bind callback function to Promise object (can even specify/multiple after asynchronous task ends) 2). Support chain call, can solve the problem of callback hell. The nested callback is called, and the result of the asynchronous execution of the external callback is the condition for the nested callback to execute b. Callback to hell's shortcomings? Not easy to read/exception handling c. promise chain call solution D. async/await ultimate solutionCopy the code
3. How do I use Promise?
1). Promise constructor: Promise (excutor) {} 2). Excutor (resolve, reject) => {} 3). Reject => {} 5).promise.prototype.then method: (onResolved, onRejected) => {} 6). OnResolved => {} 7). Prototype. Catch method: (onRejected) => {} 9).promise.resolve method: (onRejected) => {} 9).promise.resolve method: (value) => {} 10).promise. Reject method: (reason) => {} 11).promise. All method: (Promise) => {}Copy the code
4. How to fulfill my Promise
According to the characteristics of Promise, we can use the form of anonymous function self-call in native JS to encapsulate our Promise constructor, so as to further study the internal implementation principle of PromiseCopy the code
1. Determine the overall structure of the Promise constructor
(function(w){/* The Promise constructor takes an executor callback that executes simultaneously at once. The executor callback can take resolve,reject */functionPromise(excutor){/* Promsie has two properties, PromiseStatus and PromiseValue. PromiseStatus is used to mark the state of preservation success or failure. The initial value is pending; PromiseValue is used to store data that is passed in the event of success or failure. Success or failure (is an opposite proposition), the initial value is undefined, so if success saves the value of success, and if failure saves the reason of failure. Const self = this // use status and data instead of self. Status = const self'pending'// Define an object to store asynchronous callback functions to be executed on success or failure. // Store two properties in one object. Self.callbacks = []} w.romise = Promise; self.callbacks = []} w.romise = Promise; })(window)Copy the code
Resolve () and Reject () methods that are called when a Promise defines success internally
functionResolve (value){// If the state is not pending, the state cannot be changed twicereturn;
if(self.status ! = ="pending") {return} //1. Change the internal state to resolve; self.status ='resolved'//2. Assign the internal data to the value passed in for success; Self.data = value //3. Execute the successful callback in the callbacks immediately and asynchronously when the callback is pending in the callback array (callback queue)if(self.callbacks.length>0){
setTimeout(()=>{self.callbacks. ForEach (callbackObj =>{/* In the Promise constructor, if the state is delayed, but at this pointthenThe success and failure callbacks in a method are defined so that the state can never be redefinedthenThe callback is listened on and never executedthenSo you can add successful or failed methods that need to be executed in a predefined array called callbacks. */ callBackobj. onResolved(value)})}}functionReject (reason){// If the state is not pending, the state has already been changed and cannot be changed againreturn;
if(self.status ! = ="pending") {return} //1. Change the internal state to resolve; self.status ='rejected'//2. Assign the internal data to the value passed in for success; Self.data = reason //3. Execute the successful callback function in callbacksif(self.callbacks.length>0){
setTimeout(()=>{
self.callbacks.forEach(callbackObj => {
callbackObj.onRejected(reason)
})
})
}
}
Copy the code
3. If an exception error occurs while excutor(the executor function) is executing, reject() should be called to return a failed method
Try {// Inside the Promise constructor, excutor() executes immediately; excutor(resolve,reject) } catch(error){ reject(error) }Copy the code
4. Define then() and catch() methods on promise.prototype
Promise.prototype.then = function(onResolved,onRejected){/* Resolve,onRejected And pass the value directly to the next Promise object (value through) */ onResolved = typeof onResolved ==='function'? onResolved : value => value;
onRejected = typeof onRejected === 'function'? OnRejected: Reason => {throw Reason} // Cache this const self = this // Store the current stateletStatus = this.status // Whichever callback is executed returns a promise object that succeeds or fails as the case may bethenMethod, becausethenMethods can be called chained.returnNew Promise((resolve,reject)=>{// extract duplicate code to encapsulate as a functionfunctionHandle (callback){// whatever enterthenResolve () and reject() are resolved when onResolved() or onRejected() is called. Resolve () and reject() are resolved when onResolved() or onRejected() is called. becausethenThe principle of method chain calls is that which callback function the current.then() enters depends on the callthenState */ try{/* According to the promisethenA method callback function that takes a parameter to the value passed in to the resolve() call, self.data; * /letResult = callback(self.data) // There are two possible cases if no exception is currently thrown //1 The promise object is returnedif(result instanceof Promise){/* Result is a Promise objectthenThe resolve() or reject() method is invoked based on the state of the rusult promise object. The resolve() or reject() method is invoked based on the state of the rusult promise object. Result. then(value => reject(), reason => reject()); So you can abbreviate it to the following form because result as a promise object always has a success or failure state that you can usethenThen (resolve,reject) return result status */ result.then(resolve,reject)}else{/ / to enterelseResolve (result)}}catch (error){resolve(result)}}catch (error){ Reject () reject(error)}} // Check the current status before deciding which callback to executeif(status === 'resolved') {setTimeout(()=>{
handle(onResolved)
})
}else if(status === 'rejected') {setTimeout(()=>{
handle(onRejected)
})
}else{/* The execution scenario here is called when the result of a success or failure in the last returned Promise object is delayedthenMethods don't go into successful or failed callback handlers, but after appending successful or failed methods to callbacks, once the last deferred Promise object returns a success or failure result, Call the array's successful or failed callback function immediately (resolve and reject) */ / Call self.callbacks. Push ({/* onResolve, onReject) */ / if (a = a,b = a,b = a) Resolve () or reject() {onResolved(value){resolve(), reject(); Handle (onResolved)}, onRejected(reason){handle(onRejected)}})})} //thenMethod only executes the second callback, everything else is the same promise.prototype.catch =function(onRejected){
return this.then(undefined,onRejected)
}
Copy the code
Define the resolve() and reject() methods on the Promise constructor
/* The promise.resolve () method returns a new Promise state based on the type of argument it passed in, or the state (if a Promise object is passed in); The promise.reject () method always returns a new Promise object in the failed state, regardless of the argument passed in. */ /* Returns a Promise object value that specifies a success value: General data or PROMISE */ promise.resolve =function(value){
return new Promise((resolve,reject)=>{
if(value instanceof Promise){
value.then(resolve,reject)
}else{resolve(value)}})} /* Return a promise object with a failed reason reason: general data /error */ promise.reject =function(reason){
return new Promise((resolve,reject)=>{
reject(reason)
})
}
Copy the code
6. Define the all() and race() methods on the Promise constructor
/* Returns a new promise object. If all of the promise objects in the array are in the successful state, the new promise succeeds. If only one of the promises in the array returns a failed state, the new promise failsfunction(promises){
returnNew Promise((resolve,reject)=>{// Define an accumulator that determines the number of successful Promise objects in the current arrayletNum = 0 // Define an array to collect all values of the returned success statusletValues = new Array(promises. Length) promises. ForEach ((item,index) promises. Processing a non-promise object according to promise.all returns its value directly, */ promise.resolve (item). Then (value => {num++ values[index] = value) Change the internal state to a successful stateif(num === promises. Length){resolve(values)}}, reason =>{// If a promise produces a failure value, Reject (reason)})})})} // Return a new Promise object, The state and value or Reason value of the first successful or failed promise object is the state and value or reason value of the new promise object, promise.race =function(promises){
returnNew Promise((resolve,reject)=>{Promise. ForEach (item =>{Promise. Resolve (item). Value => reject(value), error => reject(reason))})}Copy the code
5. The interview questions
1) Input results of the following codessetTimeout(() => {
console.log("0")
}, 0)
new Promise((resolve,reject)=>{
console.log("1")
resolve()
}).then(()=>{
console.log("2")
new Promise((resolve,reject)=>{
console.log("3")
resolve()
}).then(()=>{
console.log("4")
}).then(()=>{
console.log("5"Resolve (); resolve(); resolve()thenIt was in the previous onethenThe value is returned before it is put into the microqueue, so analyze when it is executedreturnCrucial */returnundefined; // }).then(()=>{ console.log("6")
})
new Promise((resolve,reject)=>{
console.log("Seven")
resolve()
}).then(()=>{
console.log("8"})) /* Execute the sequence: first execute the global synchronization code: 1 7 then execute the micro queue code: 2 3 8 4 6 5 Finally execute the macro queue code: 0. 1. If 1 is executed first, the first one is displayedthenPut the microqueue immediately (2, 3)then)), the secondthenIt will be placed in the callbacks, but will not be placed in the microqueue for the time being. Perform 2. When executing 7, the followingthenImmediately into the queue, (3) after execution 7, there is no global synchronization code, so start executing the queue in code 2, 3, in turn, do not belong to the queue, as long as the global synchronization code, will be immediately executed simultaneously) 8 note: after the resolve (), immediately will contain 4thenPut it in the microqueue, which contains 5thenPut it in callbacks, and executereturnUndefined (synchronous code, so will be executed first), so will immediately include the following 6then4. Execute the code in the microqueue in the order of 4 and 6. 5thenPut into the microqueue, so execute immediately after 6 (put into the microqueue one step after 6) 6. Finally, all the synchronization codes and microqueue codes are executed. Macro queue code 0 is executed in the overall order of 1, 7, 2, 3, 8, 4, 6, 5, 0 */Copy the code
6.Promise points
1) Promise.then or.catchreturnAn error object does not throw an error, so it will not be caught by a subsequent catch. Change it to one of these:return Promise.reject(new Error('error!!! '))
throw new Error('error!!! ') because any return value that is not a promise will be wrapped in a Promise object, i.ereturn new Error('error!!! ') is equivalent toreturn Promise.resolve(new Error('error!!! '))
Copy the code
This article mainly introduces the concept and usage of custom promise, welcome your criticism and correction.