callback function is that it deprives us of the ability to use keywords such as return and throw. Promise solves all of this well
Promise concept
The so-called Promise is an object provided natively by ES6, used to pass messages of asynchronous operations. It represents an event that will only know the result in the future (usually an asynchronous operation), and this event provides a unified API for further processing
directly print console.dir(Promise) Let's take a look at
. You can understand it at first glance. Promise is an constructor . You have familiar methods such as all, reject, and resolve. There are also familiar methods such as then, catch on the prototype. In this way, the objects produced by Promise new must have the then and catch methods
Promise characteristics
Promise objects have the following two characteristics
1. The state of the object is not affected by the outside world. The Promise object represents an asynchronous operation with three states: Pending (in progress), Resolved (completed, also known as Fulfilled), and Rejected (failed). Only the result of asynchronous operations can determine which state it is currently in, and no other operation can change this state. This is also the origin of the name Promise. Its English means "promise", which means that other means cannot be changed.
2. Once the state changes, it will not change again, and you can get this result at any time. There are only two possible ways to change the state of the Promise object: from Pending to Resolved and from Pending to Rejected. As long as these two situations occur, the state will not change again and will continue to maintain this result. Even if the change has already happened, you will get this result immediately after adding a callback function to the Promise object. This is completely different from an event. The characteristic of an event is that if you miss it and listen to it, you will not get any results.
With the Promise object, asynchronous operations can be expressed in the process of synchronous operations, avoiding nested callback functions at layers. In addition, the Promise object provides a unified interface, making it easier to control asynchronous operations.
Promise also has some disadvantages. First, the Promise cannot be cancelled. Once it is created, it will be executed immediately and cannot be cancelled in the middle. Secondly, if the callback function is not set, the error thrown by Promise will not be reflected outside. Third, when in the Pending state, it is impossible to know which stage it has progressed (it has just begun or is about to be completed)
new a Promise Let's take a look:
Promise constructor receives a parameter, which is a function, and passes in two parameters: resolve and reject, respectively representing the callback function after the asynchronous operation is successful and the callback function after the asynchronous operation is failed. In fact, the description of "success" and "failure" here is not accurate. According to the standard, resolve is to set the state of the Promise to fullfile, and reject is to set the state of the Promise to rejected. However, at the beginning we can understand this first, and then look at the concept in detail.
In the above code, we performed an asynchronous operation, that is, setTimeout. After 2 seconds, the output "execution is completed" and the resolve method is called.
runs the code and outputs "Execution Complete" after 2 seconds. Notice! I just new an object and did not call it, and the function we passed in was executed. This is a detail that needs to be paid attention to. So when we use Promise, we usually wrap it in a function, and run this function when needed, such as:
At the end of the function we wrapped, the Promise object will be returned, that is, if we execute this function, we get a Promise object. Remember that there are then and catch methods on the Promise object? This is the power, look at the following code:
directly calls the then method on the return of runAsync(). Then receives a parameter, which is a function, and will get the parameters we pass when we call resolve in runAsync.Running this code will output "execution completion" in 2 seconds, and then output "whatever data"
should have some understanding at this time. It turns out that the functions in then have the same meaning as our usual callback function, which can be executed after the asynchronous task of runAsync is completed. This is the function of Promise; simply put, it is to separate the original callback writing method, and after the asynchronous operation is executed, the callback function is executed in a chain call.
Of course, I encapsulate the callback function and pass it to runAsync is the same? Just like this:
So the problem is, what should I do if there are multiple layers of callbacks? What should I do if callback is also an asynchronous operation and needs to have a corresponding callback function after execution? You can't define a callback2 and then pass it in to the callback. The advantage of Promise is that you can continue to write the Promise object in the then method and return it, and then continue to call then to perform callback operations.
usage of chain operations
On the surface, Promise can only simplify the writing of layers of callbacks. In essence, the essence of Promise is "state". The method of maintaining state and passing states can enable callback functions to be called in time. It is much simpler and more flexible than passing callback functions. So the correct scenario of using Promise is as follows:
This way, the content in each asynchronous callback can be output in order every two seconds, and the data passed to resolve in runAsync2 can be obtained in the next then method. The running result is as follows:
Guess how the three functions of runAsync1, runAsync2, and runAsync3 are defined.
In the then method, you can also directly return the data instead of the Promise object, and you can receive the data in the later then. For example, we modified the above code to this:
, and the running result is as follows:
Basic api
Promise.resolve()
Promise.reject()
Promise.prototype.then()
Promise.prototype.catch()
Promise.all() // All completed
Promise.race() // Race, complete one
reject usage
has the most basic understanding of Promise. Let’s take a look at what other features of the ES6 Promise. We just used resolve, but not reject. In fact, our previous examples were only called backs with "successful execution" and there was no "failure". The role of reject is to set the state of the promise to rejected, so that we can catch it in then and then execute the callback of the "failure" situation. Look at the code below. The
getNumber function is used to obtain a number asynchronously. The execution is completed after 0.5 seconds. If the number is less than or equal to 5, we think it is "successful". Call resolve to modify the status of the Promise. Otherwise, we think it is "failed", call reject and pass a parameter, as the reason for the failure
runs getNumber and passes two parameters in then. Then method can accept two parameters, the first corresponding to resolve callback, and the second corresponding to reject callback
catch usage
Promise object, in addition to the then method, there is also a catch method. In fact, it is the same as the second parameter of then, used to specify the callback of reject, the usage is as follows: the effect of
is the same as written in the second parameter of then. However, it has another function: when executing the resolve callback (that is, the first parameter in then), if an exception is thrown (the code error occurs), it will not report an error and js stuck, but will enter this catch method
. In the resolve callback, we console.log(somedata); and the somedata variable is not defined. If we don't use Promise, the code will report an error directly on the console and will not run down. In other words, it goes into the catch method and passes the error cause to the reason parameter.Even if there is an error, it will not report an error. This has the same function as our try/catch statement. The usage of
all is
Promise's all method provides the ability to execute asynchronous operations in parallel, and the callback is executed only after all asynchronous operations are executed. We still use the three functions defined above: runAsync1, runAsync2, and runAsync3
Promise.all([runAsync1(), runAsync2(), runAsync3()]).then(function(results){console.log(results);
uses Promise.all to execute. All receives an array parameter, and the values inside are eventually considered to return to the Promise object. In this way, three asynchronous operations are executed in parallel, and they will only enter then after they are executed. So, where is the data returned by the three asynchronous operations? All are in then, all will put the results of all asynchronous operations into an array and pass them to then, which is the results above. So the output result of the above code is:
Asynchronous task 1 is executed and completed. With all, you can execute multiple asynchronous operations in parallel, and in one All return data is processed in the callback. There is a scenario that is very suitable for using this. Some applications with more game materials. When opening a web page, various resources that need to be used are loaded in advance, such as pictures, flash and various static files. After all, we initialize the page. The usage ofrace. The effect of
all method is actually "who runs slowly, executes callbacks based on whom", so there is another method "who runs fast, executes callbacks based on whom", which is the race method, which is the meaning of race. The usage of race is the same as all. Let's change the delay of runAsync1 above to 0.2 seconds to see:
Promise.race([runAsync1(), runAsync2(), runAsync3()]).then(function(results){console.log(results);'s three asynchronous operations are also executed in parallel. As a result, you should be able to guess that after 0.2 seconds, runAsync1 has been executed, and then the one in then is executed. The result is as follows:
asynchronous task 1 is completed. When the callback in then starts to execute, runAsync2() and runAsync3() have not stopped and are still executing. So after another 0.3 seconds, the flag of their end is output. There are still many usage scenarios forraces, such as we can use race to give a certain asynchronous one. Please Find the timeout time and execute the corresponding operation after the timeout. The code is as follows:
requestImg function will request an image asynchronously. I wrote the address as "xxxxxx", so it is definitely impossible to request it successfully. The timeout function is an asynchronous operation with a delay of 5 seconds. We put these two functions that return the Promise object into race, so they will race. If the image request is successful within 5 seconds, then enter the then method and execute the normal process. If the image has not been successfully returned in 5 seconds, then timeout will outperform, then enter the catch and report the information of "image request timeout"
summary
ES6 These are basically what you can use in Promise. done, finally, success, fail, etc. are not in the Promise standard, but the syntax sugar that we implement ourselves
All asynchronous operations in this article take setTimeout as an example. The reason why we do not use ajax is to avoid confusion, because when talking about ajax, many people's first reaction is ajax of jquery, and jquery has its own Promise implementation. If you understand the principle, you know that using setTimeout is the same as using ajax