Promise is a constructor with familiar methods all, Reject, and resolve on its own, and equally familiar methods like THEN and catch on its prototype. Let’s have a new one:

Const p = new Promise((resolve, reject) => {// do something asynchronous setTimeout(() => {console.log(' done '); Resolve (' whatever data '); }, 2000); });Copy the code

Promise’s constructor takes one argument, which is a function, and passes two arguments, resolve and reject, which represent the successful and unsuccessful callback of the asynchronous operation. In fact, “success” and “failure” are not accurate descriptions. According to the standard, resolve is the state of a Promise fullfiled, reject is the state of a Promise rejected. But we can think of it this way at the beginning, and we’ll get into the concepts later. In the above code, we perform an asynchronous operation, setTimeout, and after 2 seconds, print “Execution complete” and call the resolve method. Running the code will print “Execution completed” after 2 seconds. Attention! I’m just new an object, I’m not calling it, and the function we passed in is already executed, so that’s a fine detail to notice. So when we use promises, we usually wrap them in a function and run the function if we need to, like:

Function runAsync(){const p = new Promise(resolve, reject) => {setTimeout(() => {console.log(' done '); Resolve (' whatever data '); }, 2000); }); return p; } runAsync();Copy the code

You should have two questions:

1. What’s the use of wrapping such a function? 2. Resolve (‘ whatever data ‘); Is this made of dry wool?

Let’s move on. At the end of our wrapped function, we return a Promise object, that is, we get a Promise object by executing this function. Remember the then and catch methods on Promise objects? This is where the power comes in. Look at the following code:

runAsync().then(data => { console.log(data); // you can do some other things with the data //...... });Copy the code

Call the then method directly on the return of runAsync(). The then takes an argument, which is a function, and takes the argument we passed to resolve in runAsync. Running this code will output “execution completed” two seconds later, followed by “whatever data.”

The then function is a callback function that can be executed after a runAsync task has finished executing. That’s where Promise comes in. In a nutshell, it’s the ability to separate out the original callback writing and execute the callback as a chain call after the asynchronous operation.

You might dismiss it, but is that all a big Promise can do? I wrapped the callback function and passed it to runAsync as well, like this:

Function runAsync(callback){setTimeout(() => {console.log(' done '); Callback (' whatever data '); }, 2000); } runAsync(data => { console.log(data); });Copy the code

The effect is the same. Why bother using Promise. So the question is, what do you do with multiple layers of callbacks? What if callback is also an asynchronous operation that requires a callback function after execution? You can’t define a callback2 and pass it to the callback. The advantage of promises is that you can continue writing the Promise object in the THEN method and return it, and then continue calling the THEN for callback operations.

The use of chain operation

Therefore, on the surface, Promise can only simplify the writing method of layer upon layer callback. In essence, the essence of Promise is “state”, which can be invoked in time by maintaining state and transferring state. It is much simpler and more flexible than passing callback function. So the correct scenario for using promises looks like this:

runAsync1()
.then(data => {
    console.log(data);
    return runAsync2();
})
.then(data => {
    console.log(data);
    return runAsync3();
})
.then(data => {
    console.log(data);
});
Copy the code

This outputs the contents of each asynchronous callback every two seconds, in order, and the data passed to resolve in runAsync2 can be retrieved in the subsequent then method. The running results are as follows:

Guess how runAsync1, runAsync2, and runAsync3 are defined? Yes, here it is:

function runAsync1(){ const p = new Promise((resolve, Reject) => {// do something async setTimeout(() => {console.log(' Async task 1 completed '); Resolve (' whatever data 1'); }, 1000); }); return p; } function runAsync2(){ const p = new Promise((resolve, Reject) => {// do something async setTimeout(() => {console.log(' Async task 2 completed '); Resolve (' whatever data 2'); }, 2000); }); return p; } function runAsync3(){ const p = new Promise((resolve, Reject) => {// do something async setTimeout(() => {console.log(' Async task 3 completed '); Resolve (' whatever data 3'); }, 2000); }); return p; }Copy the code

In the THEN method, you can also return the data directly instead of the Promise object and then receive the data in the later THEN. For example, we can change the above code to look like this:

runAsync1() .then(data => { console.log(data); return runAsync2(); }) .then(data => { console.log(data); Return 'directly return data '; }). Then (data => {console.log(data); });Copy the code

The output then looks like this:

Reject the use of the

At this point, you should have a basic idea of what promises are. So let’s take a look at what else ES6 Promises can do. We’ve just used resolve, not reject, what does it do? In fact, all of our previous examples are ‘execute successfully’ callbacks, with no ‘fail’ yet. Reject sets the Promise state to rejected, so we can catch the ‘fail’ callback in THEN. Look at the following code:

function getNumber(){ const p = new Promise((resolve, Reject) => {// do something asynchronous setTimeout(() => {const num = math.ceil (math.random ()*10); If (num <=5){resolve(num); } else {reject(' numbers are too large '); }}, 2000); }); return p; } getNumber() .then(data => { console.log('resolved'); console.log(data); }, (reason, data) => { console.log('rejected'); console.log(reason); });Copy the code

If the number is less than or equal to 5, we consider it a “success” and call resolve to change the state of the Promise. Otherwise we consider it a “failure,” call Reject and pass an argument as the reason for the failure. Run getNumber and pass two arguments in THEN. The then method accepts two arguments, the first for the resolve callback and the second for the reject callback. So we were able to get the data separately from them. Run this code many times and you will get one of two random results:

or

The use of the catch

We know that a Promise object has a catch method as well as a then method, so what does that do? This, like the second argument to then, specifies the reject callback, as follows:

getNumber()
.then(data => {
    console.log('resolved');
    console.log(data);
})
.catch(reason => {
    console.log('rejected');
    console.log(reason);
});
Copy the code

The effect is the same as in the second argument to then. However, it also serves another purpose: if an exception is thrown when the resolve callback (the first argument to then above) is executed, it does not trap the JS, but instead goes into the catch method. Take a look at the following code:

getNumber() .then(data => { console.log('resolved'); console.log(data); console.log(somedata); // someData undefined}). Catch (reason => {console.log('rejected'); console.log(reason); });Copy the code

In the resolve callback, we console.log(somedata); The variable someData is undefined. If we don’t use the Promise, the code will run here and we’ll just get an error on the console and stop running. But here, you get something like this:

That is, it is inside the catch method and passes the cause of the error to the reason argument. Even if the code has an error, it will not report an error, which has the same functionality as our try/catch statement.

All the usage of the

Promise’s All method provides the ability to execute asynchronous operations in parallel and not execute callbacks until all asynchronous operations have been executed. We still use the three functions defined above, runAsync1, runAsync2, runAsync3, as shown in the following example:

Promise.all([runAsync1(), runAsync2(), runAsync3()])
.then(results => {
    console.log(results);
});
Copy the code

All, which takes an array of arguments, and the values in it will eventually return a Promise object. Thus, three asynchronous operations that are executed in parallel do not enter the then until they are all executed. So where is the data returned by the three asynchronous operations? It’s all inside then, so all will put the results of all the asynchronous operations into an array and pass it to THEN, which is what results is above. So the output of the above code is:

The use of the race

The effect of the all method is essentially “the slowest runner executes the callback,” as opposed to the “fastest runner executes the callback,” which is the race method, which is the word for race. Race is the same as all. Let’s change the runAsync1 delay to 1 second:

Promise.race([runAsync1(), runAsync2(), runAsync3()])
.then(results => {
    console.log(results);
});
Copy the code

These three asynchronous operations are also executed in parallel. As you can probably guess, one second later runAsync1 is finished executing, and then is executed. The result is this:

Did you guess right? Not quite, is it? RunAsync2 () and runAsync3() do not stop when the callbacks in then start executing and continue. So after another second, output their end sign. What is the use of this race? There are many different scenarios. For example, we can use Race to set a timeout for an asynchronous request and perform the corresponding operation after the timeout. The code is as follows:

Function requestImg(){const p = new Promise((resolve, reject) => {const img = new Image(); img.onload = () => { resolve(img); } img.src = 'xxxxxx'; }); return p; } function timeout(){const p = new Promise(resolve, reject) => {setTimeout(() => {reject(' reject ')); }, 5000); }); return p; } Promise .race([requestImg(), timeout()]) .then(results => { console.log(results); }) .catch(reason => { console.log(reason); });Copy the code

The requestImg function asynchronously requests an image, and I wrote the address as “XXXXXX”, so it will definitely fail. The timeout function is an asynchronous operation with a delay of 5 seconds. We put the two functions that return the Promise object into race, and they race. If the image request is successful within five seconds, then the normal process is followed. If the image is not returned within 5 seconds, timeout wins and a catch message is displayed indicating that the image request has timed out. The running results are as follows: