Write at the front: This is one I wrote about the JS series, an article will not just only speak a knowledge point, main hope you don’t feel like talking so many things suddenly, see will be upset, because I usually will have associated knowledge together, so, learn knowledge will make you feel very coherent, I also want to record their own learning through the series, While sharing their own learning, mutual encouragement! If possible, please also give me a like, your like can also make me work harder to update!

An overview of

  • Serving time: 15-20 minutes

  • Difficulty: Easy, don’t run, watch before you walk

  • How to eat: Learn gradually about the concept, how to use them, their characteristics, their pain points, as well as the latest promise.any () and promise.allsettled ().

  • Foreshadowing knowledge:

    If you don’t know about synchronous task and asynchronous task, you can take a look at my blog, this article understand JS series (6) micro task and macro task, Event Loop,

    ② If the instance object, prototype, prototype chain do not understand the students can refer to my article this article to understand THE JS series (seven) of the constructor, new, instance object, prototype, prototype chain, ES6 class

Using the environment

A Promise is essentially a constructor, because it is created using the new keyword, and it is a solution to asynchronous programming that is more rational and powerful than the traditional solutions — callbacks and events — and belongs to a concept in ES6.

In short, a Promise is a container for asynchronous operations that can be used to gracefully retrieve the results of asynchronous operations. Of course, you can also play synchronous operation, yes, but not recommended. After all, synchronization tasks can usually be written straight away; there’s no need for a Promise shell.

So, promises are typically used for $Ajax data requests that encapsulate HTTP requests, such as the following (data requests made in Axios)

// Send data to background
export const postData= (params) = > {
  return new Promise((resolve, reject) = > {
    axios.post('/xxxUrl', params).then(res= >{
      resolve(res)})
      .catch(error= >{reject(error)}); })};Copy the code

Three states

Promise instances have three states:

  • pending

    In progress, this is an initial state after the Promise instance is created.

  • fulfilled

    Has been successful. The state reached after calling resolve in the executor.

  • rejected

    Has failed. The state reached after reject is called in the executor.

This is certainly understandable, as you do things, in the beginning is ongoing, in the end, there is only success or failure.

In the example above, postData is an instance of a Promise. After a new Promise, its state is pending, and its state changes only when the axios. Post network request succeeds or fails. This second state depends on the result of the network request.

Promise.prototype

  • Promise.prototype.then()

    The then method is simply the result of the resolve() callback, which is the successful callback function.

  • Promise.prototype.catch()

    The catch method is simply the product of the reject() callback, the callback function in the failed state.

  • Promise.prototype.finally()

    The finally method is simply a callback function that is executed regardless of success or failure.

features

1. Executed immediately

Once a Promise instance is created, the logic in the executor executes immediately, deciding how to use resolve or reject to change the state of the Promise instance based on the result returned by the async. How to understand the following sentence, first look at an example

  const promise = new Promise(function(resolve, reject) {
    console.log('start');
    if (true){
      resolve('success');
    } else {
      reject('error');
    }
    console.log('end');
  });
  
  promise.then(res= >{
    console.log(res);
  })
Copy the code

The console will output start at the start, because the Promise will execute immediately after it is created, and then end. Wait until all the synchronous tasks have been processed before processing the asynchronous tasks. So I output success, which looks like this

start => end= > success
Copy the code

2. commitment

It also has a great characteristic of its own, that is, it is not influenced by the outside world.

Only the result of an asynchronous operation can determine the current state, which cannot be changed by any other operation. That’s where the name “Promise” came from, meaning “Promise” in English, meaning it can’t be changed by other means.

3. Result uniqueness

A success triggers a THEN, a failure a catch, and no result is obtained if the status is inconsistent. Consider the following example

const promise = new Promise(function(resolve, reject) {
    console.log('start');
    if(true){
        resolve('success');
    }else{
        reject('error');   
    }
    console.log('end');
});

promise.catch(error= >{
    console.log(error);
})
Copy the code

Since the Promise has a resolve callback, the success state, only then() will be invoked and no catch will be triggered.

So, the program runs as start => end, and catch() doesn’t execute at all.

Not only that, of course, but once a Promise changes its state, it never changes again. Let’s rewrite the code above. To differentiate, we use reject() and then call resolve()

  const promise = new Promise(function(resolve, reject) {
    console.log('start');
    reject('error');
    resolve('success');
    console.log('end');
  });
  
  promise.then(res= >{
    console.log(res);
  }).catch(error= >{
    console.log(error);
  })
Copy the code

Since a state changes, it does not change again, so it has, only and always is the result of the first change, and the first execution is reject, which is a failed state.

So, the above output is start => end => error

Promise.all()

The promise.all () method is used to wrap multiple Promise instances into a new one

For example, three instance methods of postData are defined as follows

const dataList = Promise.all([postData1(),postData2(),postData3()])
Copy the code

This will be fulfilled only when all requests are successful. Then the return values of postData1, postData2, and postData3 will form an array and be passed to the callback function of the dataList.

Whenever a request fails, the dataList state becomes Rejected, and the return value of the first rejected instance is passed to the dataList callback function.

Usage scenario:

Three interfaces are respectively, for example, pull the language, mathematics, English educational interface, so, we need to return through the three interfaces, calculated the score of students finally, at the moment with all () is very reasonable, because the value of the three interfaces are short of one cannot, if there is an error, won’t get a score, will go catch (), Then, the prompt is which grade data is not available, affecting the final score calculation.

Promise.race()

The promise.race () method also wraps multiple Promise instances into a new one.

const dataList = Promise.rece([postData1(),postData2(),postData3()])
Copy the code

In the code above, if one of the three Promise instances changes the state first, then the state of the dataList will also change, which means I will use the one who is faster

Usage scenario:

(1) When an interface has three request interface addresses and the data requested is consistent, this method can be used to ensure the matching of the fastest interface speed.

SetTimeout (() => Reject (new Error(‘request timeout’)), 5000)), reject(() => reject(new Error(‘request timeout’)), 5000) PostData1 () must complete within 5 seconds or it will fail

const dataList = Promise.race([
  postData1(),
  new Promise(function (resolve, reject) {
    setTimeout(() = > reject(new Error('request timeout')), 5000)})]);Copy the code

Promise.allSettled()

The promise.allsettled () method also wraps multiple Promise instances into a new one. (ES 2020 features)

This will be fulfilled someday or never until all of these parameter instances return the result, which will eventually be returned as an array. And whether the argument instance succeeds or fails, it always goes.then(), without.catch(), and returns something like this after success:

[{status: 'fulfilled'.value: 42 },
   { status: 'rejected'.reason: -1}]Copy the code

Each object has a status attribute, which can only be the string Fulfilled or the string Rejected. This is fulfilled, when the object has a value attribute and a Reason attribute when it has rejected, which corresponds to the return value of the two states.

Therefore, the status method can be used to distinguish the success or failure of the parameter instance.

success = results.filter(p= > p.status === 'fulfilled')
error = results.filter(p= > p.status === 'rejected')
Copy the code

Usage scenario:

We don’t care about the result of the interface, we just care that the operation ends.

Promise.any()

The promise.any () method also wraps multiple Promise instances into a new one. (ES 2021 features)

As long as one of the parameter instances succeeds, the wrapper instance becomes successful; The wrapper instance is in a failed state only if all parameter instances fail.

Usage scenario:

Not figured out, to be added

Problems with nesting

Promise is a powerful feature, but sometimes our interfaces need to be executed sequentially. For example, if we want to pull the first interface, pull the second interface with the parameters of the first interface, and then pull the third interface, we need to execute sequentially

getData1(' ').then(res1= >{
    getData2(res1.data.id).then(res2)=>{
        getData3(res2.data.id).then(res3= >{})}})Copy the code

Of course, with the complexity of the project, sometimes four or five layers may be required, although this should be relatively rare. This is called callback hell, with the concept of closures, where results from the inside can be accessed from the outside, and data is returned from layer after layer of interfaces, making maintenance head-spinning.

Modify the time to see the bottom is to change a few layers of code, to prevent the wrong place to change.

Chain calls

In fact, promises are designed to solve the problem of callback hell, so you can use chained calls to solve the problem of nesting.

The.then() callback returns a Promise, so it can always be a.then().

getData1().then(res= >{
  console.log(res)  // data1
  return getData2();
}).then(res= >{
  console.log(res) // data2
  return getData3();
}).then(res= >{
  console.log(res) // data3
})
Copy the code

Chained callbacks are much cleaner than nested callbacks and more like synchronous code.

Of course, the next blog post will talk about Generator and eventually the most elegant way to async await.

Finally, welcome everyone to pay attention to my personal public number front big canteen

reference

Ruan Yifeng ECMAScript 6 Introduction – Promise

Series directory

  • This article understands JS series (a) compilation principle, scope, scope chain, variable promotion, temporary dead zone

  • This article understands JS series (2) JS memory life cycle, stack memory and heap memory, depth copy

  • JS series (3) to understand the garbage collection mechanism, memory leaks, closures

  • Understand JS series (four) closure application – Currie, partial function

  • Understand JS series (five) closure application – tremble, throttling

  • JS series (6) micro task and macro task, Event Loop

  • JS series (7) constructor, new, instance object, prototype, prototype chain, ES6 class

  • JS series (8) easy to understand the Promise

  • Learn more elegant asynchronous solutions in JS series (9)