This article mainly introduces detailed information about asynchronous JavaScriptPromises. For more information, see. So far, every JavaScript developer and their grandmother may have heard of Promises. If you do not have one, you are about. The concept of promises was proposed by members of the CommonJS team in the Promises/A specification. Promises is gradually used as a method for managing Asynchronous Operation callbacks, but out of their design, they are far more useful than that. In fact, due to their many usage, many people have told me that after I wrote something about promises, I "missed the focus of promises ". So what is the focus of promises?
Something about Promises
Before I start promise's "Focus", I think I should show you how they work internally. A promise is an object-according to Promise/A specifications-only one method is required: then. The then method has three parameters: one success callback, one failure callback, and one forward callback (the standard does not require the implementation of forward callback, but many of them are implemented ). A new promise object is returned from every then call.
A promise can be in one of three states: incomplete, complete, or failed. Promise starts with an incomplete state. If it succeeds, it will be in the completed state. If it fails, it will be in the failed State. When a promise is moved to the completion state, all successful callbacks registered to it will be called and the successful result value will be passed to it. In addition, any successful callback registered with promise will be called immediately after it is completed.
The same thing occurs when the promise moves to the failed State, except that it calls a failed callback rather than a successful callback. For the implementation that includes the forward feature, promise can update its progress at any time before it leaves the unfinished state. When progress is updated, all forward callbacks (progress callbacks) are passed with the value of progress and called immediately. The forward callback is processed in a different way than the success or failure callback. If you register a forward callback after a progress update has occurred, the new forward callback will only be called by the updated SS after it is registered.
We will not go further into how the promise status is managed, because it is not within the specifications, and each implementation is different. In the following example, you will see how it is done, but this is all you need to know.
Processing callback
As mentioned above, asynchronous callback processing is the most basic and common use of promises. Let's compare a standard callback with a callback using promise.
// Normal callback usageasyncOperation(function() { // Here's your callback});// Now `asyncOperation` returns a promiseasyncOperation().then(function(){ // Here's your callback});
I doubt whether someone will really care about using promises if I see this example. It seems that there is no benefit, except for "then", which makes the callback function called after the asynchronous operation is completed more obvious. But even for this benefit, we now have more code (abstraction should make our code shorter, isn't it ?) In addition, promise is slightly inferior to standard callback.
But don't let it block you. If this is the best thing promise can do, this article will not exist.
Pyramid of bad luck
// Normal callback usage => PYRAMID OF DOOOOOOOOMasyncOperation(function(data){ // Do some processing with `data` anotherAsync(function(data2){ // Some more processing with `data2` yetAnotherAsync(function(){ // Yay we're finished! }); });});// Let's look at using promisesasyncOperation().then(function(data){ // Do some processing with `data` return anotherAsync();}).then(function(data2){ // Some more processing with `data2` return yetAnotherAsync();}).then(function(){ // Yay we're finished!});
As you can see, the use of promises makes things flat and readable. This works because -- As mentioned earlier -- then returns a promise, so you can continuously concatenate then calls. The promise returned by then loads the value returned by the call. If the call returns a promise (as in this example), the promise returned by then loads the same value as the promise returned by your callback. This is a lot of content, so I will help you understand it step by step
An Asynchronous Operation returns a promise object. Therefore, we call then in the promise object and pass it a callback function; then also returns a promise. When the asynchronous operation ends, it will load data on promise. Then (for the first time) the callback is called and the data is passed as a parameter. If the callback does not contain a returned value, the promise returned by then will be assembled immediately without a value. If the callback does not return a promise, the value of the promise returned by then is immediately loaded. If the callback returns a promise (as in the example), the promise returned by then will wait until the promise returned by the callback is fully loaded. Once the callback promise is loaded, the loaded value (data2 in this example) will be submitted to the then promise. Then, the promise in then loads data2. And so on. It sounds complicated, but in fact it is very simple. If you cannot understand what I said, I am very sorry. I guess I may not be the best person to talk about it.
Use the named callback instead.
But it is clear that promises is not the only way to flatten this structure. After I wrote a post about promises's solution to the pyramid problem of bad luck, Someone commented on the post and said ......
I think promises is sometimes useful, but the question of "nested" Callback (Christmas Tree Syndrome) can be solved by simply using a named function as a parameter to replace an anonymous function:
asyncCall( param1, param2, HandlerCallback );function HandlerCallback(err, res){// do stuff}
Its example only provides a deep example, but it is still correct. Let's extend the example above to make it look easier.
Name callback
// Normal callback usage => PYRAMID OF DOOOOOOOOMasyncOperation(handler1);function handler1(data) { // Do some processing with `data` anotherAsync(handler2);}function handler2(data2) { // Some more processing with `data2` yetAnotherAsync(handler3);}function handler3() { // Yay we're finished!}
Look at the above Code! They are absolutely right! It is a flat structure, but the problem also exists in the old callback example that I have never noticed before: dependency and reusability. Dependency and reusability are mutually correlated reversible types. The less dependent a thing, the greater its reusability. In the preceding example, handler1 depends on handler2 and handler2 depends on handler3. this means that handler1 cannot be used for any purpose unless handler2 is also displayed. If you are not planning to reuse them, what is the significance of naming your functions?
The worst thing is that handler1 does not care about what happened in handler2. It does not need handler2 to work asynchronously with it at all. Therefore, let's eliminate these dependencies and use promise to make functions more reusable.
Chained callback
asyncOperation().then(handler1).then(handler2).then(handler3);function handler1(data) { // Do some processing with `data` return anotherAsync();}function handler2(data2) { // Some more processing with `data2` return yetAnotherAsync();}function handler3() { // Yay we're finished!}
Does this look much better? If another function exists, handler1 and handler2 are irrelevant. Want to see if they are really great? Now handler1 can be used without handler2. On the contrary, after handler1 is operated, we can use another handler.
Reusable Functions
asyncOperation().then(handler1).then(anotherHandler);function handler1(data) { // Do some processing with `data` return anotherAsync();}function anotherHandler(data2) { // Do some really awesome stuff that you've never seen before. It'll impress you}
Now handler1 has been detached from handler2 and can be used in more scenarios, especially those functions provided by handler2 that we don't want to use. This is reusability! The only way the reviewer solves the Code's ease of attention is by eliminating indentation. We don't want to eliminate indentation just for indentation. Multi-level Indentation is only a sign of something wrong, and the problem is not necessarily in itself. He is like a headache caused by dehydration. The real problem is dehydration, not a headache. The solution is to obtain hydrate instead of using some painkillers.
Parallel asynchronous operations
In the previous article, I compared promises with events in asynchronous operations. Unfortunately, according to the comments given by those who have mentioned it, I am not very successful. I described the power of promises, and then turned to events to describe their power, as I used in my special project. No comparison and comparison. One reviewer wrote (modifying a syntax error ):
I want to use the example in the post as a bad comparison. A thesis proves what the value of promises will look like. If you press the fictitious "start server button", it will not only start a web server, but also a database server, when they are all running, they only update the UI.
Using the promise. when method will make this "multiple asynchronous operations" example become common. However, responding to multiple asynchronous events requires an uncommon amount of code.
He is completely correct. In fact, I have not compared the two cases. The main point of this article is that promises is not the only mechanism of asynchronous operations, and in some cases they are not necessarily the best. Under the circumstances pointed out by this reviewer, promises is of course the best solution. Let's see what he is talking about.
JQuery has a method named when, which can carry any number of promise parameters and return a single promise. If any promise fails to be passed in, the promise returned by when will also fail. If all promises are loaded, each value is passed to the attached callback in the order defined by promises.
It is very useful to execute countless asynchronous operations in parallel, and then continue to execute the callback after each of them ends. Let's look at a simple example.
JQuery. when
// Each of these async functions return a promisevar promise1 = asyncOperation1();var promise2 = asyncOperation2();var promise3 = asyncOperation3();// The $ refers to jQuery$.when(promise1, promise2, promise3).then( function(value1, value2, value3){ // Do something with each of the returned values });
It is often said that this is one of the best things promises brings and is also a part of the significance of promises. I also think this is a good feature that simplifies a lot of operations, but the mechanism of this when method is not mentioned in any Promises specification at all, so I don't think it is the meaning of Promises. One criterion mentions the when method, but it is completely different from the above. As far as I know, jQuery is the only library that implements this when method. Other promises libraries, such as Q, Dojo, and when, implement the when method according to Promises/B spec, but do not implement the when method mentioned by the annotator. However, the Q library has an all method, when. js also has a parallel method, which is similar to the preceding jQuery. the when method works the same, but they only accept an array type parameter, rather than any number of parameters.
Value Representation
Promise is a better way to deal with the following scenarios:
"I want to find a user in this database, but the find method is asynchronous. "
Therefore, here we have a find method that cannot return values immediately. But in the end it does "return" A value (via a callback), and you want to process that value in some way. Now, by using a callback, you can define a continue part, or "some code that will process that value in the future"
Promise changed the "Hey, here is some code you will find to process the returned value ". They allow the "find" method to say, "Hey, I will be busy looking for the information you are looking for, but at the same time, you can continue to wait for the returned results, and you can handle it in any way you want at the same time, just like the actual thing!"
Promise represents a real value. That is a trap. They work when you process Promise as you do. The JavaScript Implementation of Promise expects you to pass a callback function to it. This is just a "coincidence" and it is not important.
I believe this is really the focus of promise. Why? In the first sentence of the read-only Promise/A specification, "A promise represents the final value returned after an operation is completed. "Makes it a little obvious, isn't it? Well, even if that is the focus, it cannot prevent me from presenting others' opinions in the following article. In any case, let's talk more about this idea.
Conclusion
The focus of promise is that it represents the final result value returned by an operation, but the reason for using them is to make the synchronization operation more parallel. Since asynchronous programming entered this scenario, pop-up Callbacks are everywhere, covering our code in a strange way. Promise is a way to change it. Promise allows us to write code synchronously and asynchronously execute the code.