In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces "how to understand Promise". In daily operation, I believe many people have doubts about how to understand Promise. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful for you to answer the doubts about "how to understand Promise"! Next, please follow the editor to study!
A rough shelf
Through the promise syntax we often write, we can first write a general shelf. Promise accepts callbacks and calls, with three states, pendding, onFulfilled, and onRejected, and resolve function can change pendding state to onFulfilled state. Similarly, reject function can change pendding state into onRejected state. Let's implement some of the above description first.
Const PromiseCopy = function (fn) {this.info = {status: "pending", value: "",}; const self = this; self.onFulfilledArr = []; / / the collection of the first callback function in the then function self.onRejectedArr = [] / / the set of the second callback function in the / / then function const resolve = function (value) {/ / adds this judgment to indicate that it will only be executed in the pendding state. / / after the state has become onFulfilled, it cannot be changed / / in accordance with the 2.1.2.1 if (self.info.status = = "pending") {self.info.status = "onFulfilled" in PromiseA+. Self.info.value = value; self.onFulfilledArr.forEach ((fn) = > fn (value));}}; / / same as above, PromiseA+,2.1.3.1 const reject = function (value) {if (self.info.status = = "pending") {self.info.status = "onRejected"; self.info.value = value Self.onRejectedArr.forEach ((fn) = > fn (value));}}; fn (resolve, reject);}
Additional implementation of resolve
In fact, there are still some functions of our resolve function that have not been implemented so far. We know that there are several cases in which the value of x is called resolve (x), as follows.
If x is the Promise instance itself, an error is thrown
If x is a Promise object, then the execution of the then function depends on the state of the x. If x also calls resolve (y), where y is also a promise object. Then the execution of the then function depends on the promise object, and so on, until the last promise state changes.
If x is a thenable object, that is, an object contains the property then, or a function contains a static method of then, then execute the then function directly
If x is a normal value, directly change to the onFulfilled state and execute the following then function
Thinking
Most of the resolve implemented on the Internet is the code above me, but according to the specification, the above points should be judged in the resolve function, so the code we wrote above is incorrect.
Another problem is that we need to determine whether x is the instance itself in the resolve function, but in normal resolve functions, we often pass in an argument, so there must be an intermediate function in the middle, see the following code
Const PromiseCopy = function (fn) {this.info = {status: "pending", value: "",}; const self = this; self.onFulfilledArr = []; / / the collection of the first callback function in the then function self.onRejectedArr = [] / / the collection of the second callback function in the / / then function / / _ resolve is the resolve / / that we often call, but the real implementation should be the resolve const _ resolve = function (value) {/ / this function needs to be changed / / PromiseCopy once instantiated, then self is the instance itself resolve (self, value);} / / at this point we can judge const resolve = function (promise, value) {let ifexec = false in resolve. / / first determine whether value is promise itself if (value = promise) {/ / be sure to write in TypeError or promises-aplus-tests can't run / / remember that this is the first hole. Promises-aplus-tests only recognizes the wrong form of TypeError, reject ("A promise cannot be onFulfilled with itself."). } / / value is a thenable object / / this requires Object.prototype.toString.call (value) = = "[object Object]" to judge / / otherwise resolve ([]) has a problem. I wonder if I implemented the problem if (value & & (Object.prototype.toString.call (value) = = "[object Object]" | | typeof value = "function") {/ / var promise1 = Promise.resolve (dump) .then (function () {/ / return {/ / then: (resolve) Reject) = > {/ / setTimeout () = > {/ / resolve ({/ / then: (resolve, reject) = > {/ / resolve ("aa111a") / / throw "other"; / /}, / /}); / /}); / /}, / /}; / /}); / / promise1.then (/ / (res) = > {/ / console.log (res = = "aa111a") / / console.log ("aaa"); / /}, / / (res) = > {/ / console.log (res); / / console.log ("error"); / /} / /) / / try--catch must be added here, otherwise promises-aplus-tests will keep reporting errors. This is the third big pit / / because there is this one in the promises-aplus-test test / / look at the above annotated example try {/ / get the then function const then = value.then / / if then is a function, execute this function if (typeof then = "function") {/ / Why. Call (value, x, y) you can try the native Promise yourself. In this case, this points to value, so bind / / because we have taken out then = value.then and directly called then () This points to window / / Why do you need to bind two functions later / / according to the native Promise The then function in thenable can accept two functions resolve,reject / / only manual calls to resolve and reject will perform the following .then operations, specifically then.call (value, function (value) {if (ifexec) {return) } / / ifexec must be added, otherwise 200ms error will also be reported. The fourth big pit / / is to prevent multiple execution. See the following example / / var promise1 = Promise.resolve (dump). Then (function () {/ / return {/ / then: (resolve, reject) = > {/ / resolve ("aa111a") / / resolve ("aa111a"); / /}, / /}; / /}); ifexec = true; resolve (promise, value) }, function (value) {if (ifexec) {return;} ifexec = true; reject (value);}); return }} catch (e) {if (ifexec) {return;} ifexec = true; reject (e) }} / / the following is very important, which is the core of async,await and some plug-ins such as saga, that is, if x is a promise object, then the execution of then depends on the status of x / / and this judgment must be placed here, or promises-aplus-tests will report an error exceeding 200ms. Remember that this is the second pit if (value & & value instanceof PromiseCopy & & value.then = promise.then) {/ / give the onFulfilledArr of promise to value / / but it's not that simple. We need to understand two things / / if the promise of value is no longer pendding, it's useless for us to give it to him. So you need to call if (value.info.status = = "pending") {value.onFulfilledArr = self.onFulfilledArr directly. Value.onRejectedArr = self.onRejectedArr;} / / if the value state is onFulfilled if (value.info.status = = "onRejected") {self.info.value = value.info.value; self.onRejectedArr.forEach ((fn) = > fn (value.info.value)) } / / if the value status is reject if (value.info.status = "onFulfilled") {self.info.value = value.info.value; self.onFulfilledArr.forEach ((fn) = > fn (value.info.value));} return } / / if it is a normal value / / add this judgment to indicate that it will only be executed in the pendding state / / after the state has become onFulfilled, it cannot be changed / / in accordance with 2.1.2.1 if (self.info.status = = "pending") {self.info.status = "onFulfilled"; self.info.value = value in PromiseA+. Self.onFulfilledArr.forEach ((fn) = > fn (value));}}; / / in line with the above, PromiseA+,2.1.3.1 / / reject does not have as many rules as resolve, and it is relatively simple: const reject = function (value) {if (self.info.status = = "pending") {self.info.status = "onRejected"; self.info.value = value Self.onRejectedArr.forEach ((fn) = > fn (value));}}; / / at this time fn calls _ reoslve / / this try catch mainly implements promiseCopy.prototype.catch try {fn (_ resolve, reject);} catch (e) {setTimeout (()) = > {self.onRejectedArr.forEach ((fn) = > fn (e);});}}
The realization of then
What we introduced above is the resolve use of promise, and another basic use of promise is to be followed by then. Then we think of this then method attached to the prototype, so we can get this then when new PromiseCopy. In then, there are two functions, one is the callback after onFulfilled, and the other is the callback after onRejected. The question now is how does he manage that the functions in then are executed after resolve and reject? This postponement of execution, or in some cases, implementation, what we think of is the observer model. Let's use the code to implement the above words, and a more detailed comment will be written in the code.
PromiseCopy.prototype.then = function (onFulfilled, onRejected) {const self = this; / / to judge here, if PromiseCopy is resolve, then execute onFulfilled if directly (self.info.status = "onFulfilled") {setTimeout () = > {onFulfilled (self.info.value);});} if (self.info.status = "onRejected") {setTimeout (() = > {onRejected (self.info.value)) });} / according to 2.2.1.1 and 2.2.1.2 in PromiseA+, onFuller and onRejected must be functions, otherwise if (typeof onFulfilled = "function") {self.onFulfilledArr.push () = > {setTimeout (() = > {onFulfilled (self.info.value);});}) } if (typeof onRejected = "function") {self.onRejectedArr.push (() = > {setTimeout (()) = > {onRejected (self.info.value);} / / according to PromiseA+ 2.2.7 specification then function must return a promise object return new PromiseCopy ((resolve, reject) = > {});}
Additional implementation of then
The then implemented above is also a simple usage, but according to the PromiseA+ specification, this then function still has several points that have not been implemented, see the code explanation.
Promise2 = promise1.then (onFulfilled, onRejected); promise2.then (onFulfilled, onRejected)
If the onFulfilled,onRejected function in promise1.then returns an x, it is treated as [[Resolve]] (promise2, x), just like the resolve above. Note that if the function returns nothing, it is the returned undefined.
As long as one of the two callback functions in the promise1.then function reports an error, call the error callback in the promise2.then function directly
If the first callback of promise1.then is not a function and promise1 calls resolve, then the first callback parameter of promise2.then is the throw value of the resolve function in promise1
Similarly, if the second callback of promise1.then is not a function and promise1 calls reject, then the error callback in promise2.then will be executed
Thinking
If it is said above, it is a key when the newly thrown promise calls the resolve or reject, and the execution of the thrown promise also depends on the returned values of onFulfilled and onRejected. I thought about this for a long time when I wrote promise, but I didn't know how to organize it. Later, I couldn't figure it out. After reading many articles on the Internet, I found that these logic were implemented in the body of PromiseCopy.
Return new PromiseCopy ((resolve, reject) = > {})
Enhanced version of then implementation
PromiseCopy.prototype.then = function (onFulfilled, onRejected) {const self = this; / / this must be written in order to pass the value onFulfilled = typeof onFulfilled = = "function"? OnFulfilled: (val) = > val; / / this must be written this way, must throw an error throw err onRejected = typeof onRejected = "function"? OnRejected: (err) = > {throw err;}; const newnewPromise = new PromiseCopy ((resolve, reject) = > {if (self.info.status = "onFulfilled") {setTimeout () = > {try {/ / if onFulfilled is not a function resolve--self.info.value let value = self.info.value / / do not use this comment, keep it just to record the thinking at that time / / this plus judgment is to prevent the then function callback from being a function, but a string / / if (typeof onFulfilled = = "function") {/ / value = onFulfilled (value); / /} value = onFulfilled (value) / / here to do a [[Resolve]] (promise2, x) to deal with / / because it is done directly in resolve, so it is called directly, which is a little different from some implementations on the Internet / / they extract a resolvePromise function call, I directly call resolve resolve (value);} catch (e) {reject (e) }) } / / Note that according to the above, all the values thrown by onFulfilled,onRejected go through [[Resolve]] (promise2, x) / / unlike resolve,reject, resolve in promise leaves [[Resolve]] (promise2, x), and reject does not leave if (self.info.status = = "onRejected") {setTimeout (() = > {try {let {value} = self.info). Value = onRejected (self.info.value); resolve (value);} catch (e) {reject (e);}}) } / / push if is also required for pending status (self.info.status = "pending") {self.onFulfilledArr.push ((data) = > {setTimeout () = > {try {let value = data; value = onFulfilled (value); resolve (value)) } catch (e) {reject (e);}});}); self.onRejectedArr.push ((data) = > {setTimeout () = > {try {let value = data; value = onRejected (data); resolve (value)) } catch (e) {reject (e);}});});}}); return newPromise;}
Summary
At this point, the main body implementation of promise has been completed, and here are the test results
Other static methods of Promise
Promise.resolve
PromiseCopy.resolve = function (data) {return new PromiseCopy ((resolve, reject) = > {resolve (data);});}
Reject
Promise.reject = function (reason) {return new Promise ((resolve, reject) = > {reject (reason);});}
Promise.all
This method has several characteristics as follows
This method accepts an array, each element of which is a promise object
Then callbacks are executed only when all promise are onFulfilled, and the order of the results is the same as that of the array.
If reject occurs in one of the promise, then this value is returned.
PromiseCopy.all = function (data) {let count = 0; / record the number of calls let total = data.length; let result = []; return new PromiseCopy ((resolve, reject) = > {for (let I = 0; I)
< total; i++) { data[i].then( (res) =>{result.push (res); + + count; if (count = totla) {resolve (result);}}, (res) = > {return reject (res);}
Promise.race
This method also has the following characteristics
This method also accepts an array, whose element is promise
He only returns the value of the fastest promise
Even if there are errors, the value of the fastest promise will be returned.
PromiseCopy.race = function (data) {const total = data.length; return new PromiseCopy ((resolve, reject) = > {for (let I = 0; I)
< total; i++) { data[i].then( (res) =>{resolve (res);}, (res) = > {return reject (res);}
Catch method
PromiseCopy.prototype.catch = function (onRejected) {/ / those who can come into catch must be walking reject / / and the state must be pendding const self = this; const newnewPromise = new PromiseCopy ((resolve, reject) = > {if (self.info.status = = "onRejected") {try {setTimeout () = > {let {value} = self.info If (typeof onRejected = = "function") {value = onRejected (self.info.value);} resolve (value);});} catch (e) {rejetc (e) }} if (self.info.status = "pending") {self.onRejectedArr.push ((data) = > {setTimeout () = > {try {let value = data; if (typeof onRejected = "function") {value = onRejected (data);} resolve (value) } catch (e) {reject (e);}});}}); return newPromise;}; / / later found that catch has a simple implementation / / the above is not deleted in order to record the thought process Promise.prototype.catch = function (onRejected) {return this.then (null, onRejected);}
Deferred
This is a quick use provided by Promise. You must add it when you implement promise, otherwise promises-aplus-tests promise.js will not be able to run.
PromiseCopyPromiseCopy.defer = PromiseCopy.deferred = function () {let dfd = {}; dfd.promise = new PromiseCopy ((resolve, reject) = > {dfd.resolve = resolve; dfd.reject = reject;}); return dfd;}; at this point, the study of "how to understand Promise" is over, hoping to solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.