Why did promises come about?

Before Promise came along, we were processing an asynchronous network request, and the requirement looked something like this: We needed to execute a second network request based on the result of the first network request, and then execute a third one based on the result of the second network request. The demand was endless, so the code like this appeared:

request1(function(){
    // Some other operationsrequest2(function(request1The results of){
        // Some other operationsrequest3(function(request2The results of){
            // Some other operationsrequest4(function(request3The results of){
                // Some other operationsrequest5(function(request4The results of){
                    // Some other operationsrequest6(function(request5The results of){
                        // Some other operations. })})})})})})Copy the code

This is called callback hell, and the downside of callback hell is the following:

  • Code bloat.
  • Poor readability.
  • The coupling degree is too high and the maintainability is poor.
  • Poor code reuse.
  • Bug prone.
  • Exceptions can only be handled in callbacks.

At this point, someone wondered if they could solve the problem of asynchronous nesting with a more friendly code organization. The Promise specification was born, and promises took care of the pain point of callback hell by using chain calls.

We implement the above asynchronous network request using the regular writing of Promise as follows:

new Promise(request1). Then (request2Request result1). Then (request3Request result2). Then (request4Request result3). Then (request5Request result4). Then (request6Request result5To catch an exception (to catch an exception)Copy the code

It’s not hard to see that promises are written more intuitively and can catch exceptions from asynchronous functions in their outer layers.

What is a promise?

Promise is a solution to asynchronous programming that is more reasonable and powerful than traditional solutions [callback functions] and [events]. It was first proposed and implemented by the community, and ES6 has written it into the language standard, unifying usage, and providing Promise objects natively. Promise is simply a way to write code, and it’s used to write asynchronous code in JavaScript programming.

Promise has three states

Three states:

  • Pending: Pending
  • This is a big pity
  • Rejected has failed

Only the result of an asynchronous operation can determine what state it is in, and no other operation can change that state. This is where promises come from.

The state of the Promise object can change in only two ways:

  • Change from Pending to depressing
  • Change from Pending to Rejected

As soon as these two things happen the state is fixed and will not change and this is called resolved

Promise shortcomings

  1. There is no way to cancel a Promise, which is executed as soon as it is created and cannot be cancelled halfway through
  2. If no callback function is set (no errors are caught), errors thrown internally by a Promise are not reflected externally
  3. When in a pending state, there is no way to know what stage of progress is currently in (just started or about to be completed)

promise API

When we print out the Promise, we see that the Promise is a constructor with all, Reject, resolve, and race methods on its own, and then, catch, and finally methods on its prototype.

【 1 】 Promise. The prototype. The constructor ()

Its basic usage is as follows:

    let promise = new Promise((resolve, reject) = > {
      // Perform asynchronous operations here
      if (/* Asynchronous operation succeeded */) {
        resolve(success)
      } else {
        reject(error)
      }
    })Copy the code

Promise accepts a function that takes resolve and reject as arguments:

  1. The resolve method changes the Promise’s pending state to fulfilled, which can be called after the asynchronous operation succeeds. The result returned by the asynchronous operation can be passed as a parameter.
  2. The Reject method changes the pending state of a Promise to Rejected. It is called after the asynchronous operation fails, and the asynchronous result can be passed as a parameter.

Only one of them can be implemented, not both, because promises can only hold one state.

【 2 】 Promise. Prototype. Then ()

After confirming the Promise instance, you can use the THEN method to specify the callback functions of the fulfilled state and rejected state, respectively. Its basic usage is as follows:

    promise.then((success) = > {
      // The asynchronous operation was successfully executed here
      // corresponds to the resolve(success) method above
    }, (error) => {
      // Asynchronous operation failures are performed here
      // Corresponds to the reject(error) method above
    })

    // It can also be written like this (recommended)
    promise.then((success) = > {
      // The asynchronous operation was successfully executed here
      // corresponds to the resolve(success) method above
    }).catch((error) = > {
      // Asynchronous operation failures are performed here
      // Corresponds to the reject(error) method above
    })Copy the code

The then(ondepressing, onRejected) method has two parameters, both of which are functions. The first parameter executes the resolve() method, which is the callback method after asynchronous success. The second argument executes the Reject () method, which is a callback after asynchronous failure (the second argument is optional). It returns a new Promise object.

【 3 】 Promise. Prototype. The catch ()

The catch method is an alias for. Then (null, onRejected), which specifies the callback function if an error occurs. This function is the same as onRejected in then, but it can also catch the error that OnFulfilled throws, which onRejected cannot do:

    function createPromise(p, arg) {
      return new Promise((resolve, reject) = > {
        setTimeout((a)= > {
          if (arg === 0) {
            reject(p + ' fail')}else {
            resolve(p + ' ok')}},0);
      })
    }

    createPromise('p1'.1).then((success) = > {
      console.log(success) // p1 ok
      return createPromise('p2'.0)
    }).catch((error) = > {
      console.log(error) // p2 fail
    })

    createPromise('p1'.1).then((success) = > {
      console.log(success) // p1 ok
      return createPromise('p2'.0)
    }, (error) => {
      console.log(error) // Uncaught (in pomise) p2 fail
    })
Copy the code


Promise errors are “bubbling” in nature and will be thrown out until they are caught if they are not. They can’t catch errors thrown by promises that follow them.

[4] Promise. Prototype. Finally ()

The finally method is used to specify actions that will be performed regardless of the final state of the Promise object. This method is a standard introduced in ES2018:

    createPromise('p1'.0).then((success) = > {
      console.log(success)
    }).catch((error) = > {
      console.log(error) // p1 fail
    }).finally((a)= > {
      console.log('finally') // finally
    })

    createPromise('p1'.1).then((success) = > {
      console.log(success) // p1 ok
    }).catch((error) = > {
      console.log(error)
    }).finally((a)= > {
      console.log('finally') // finally
    })Copy the code

The finally method does not accept any parameters, so it is independent of the state of the Promise and does not depend on the result of the Promise execution.

[5] Promise. All ()

The promise.all method takes an array as an argument, but each argument must be an instance of Promise. Promise’s all method provides the ability to execute asynchronous operations in parallel and execute the callback only after all asynchronous operations are completed. Promise.all() returns a Promise with the Rejected state as long as one of the asynchronous operations returns a rejected state. The return value of the first reject instance is passed to the promise. all callback:

    function createPromise(p, arg) {
      return new Promise((resolve, reject) = > {
        setTimeout((a)= > {
          if (arg === 0) {
            reject(p + ' fail')}else {
            resolve(p + ' ok')}},0); })}// test: Both promises succeed
    Promise.all([createPromise('p1'.1), createPromise('p2'.1)])
      .then((success) = > {
        console.log(success) // ['p1 ok', 'p2 ok']
      }).catch((error) = > {
        console.log(error)
      })

    // test: One of the promises failed
    Promise.all([createPromise('p1'.0), createPromise('p2'.1)])
      .then((success) = > {
        console.log(success)
      }).catch((error) = > {
        console.log(error) // p1 fail 
      })

    // test: Both promises failed
    Promise.all([createPromise('p1'.0), createPromise('p2'.0)])
      .then((success) = > {
        console.log(success)
      }).catch((error) = > {
        console.log(error) // p1 fail prints only information about the first failed asynchronous operation
      })
Copy the code

[6] Promise. Race ()

Promise’s RACE method is similar to the ALL method in that it provides the ability to perform asynchronous operations in parallel. A race([P1, P2, P3]) returns a result that is faster than any other result, regardless of whether the result itself is a success state or a failure state. The following is how a race is executed:

    let p1 = new Promise((resolve, reject) = > {
      setTimeout((a)= > {
        resolve('success')},1000)})let p2 = new Promise((resolve, reject) = > {
      setTimeout((a)= > {
        reject('failed')},500)})Promise.race([p1, p2]).then((success) = > {
      console.log(success)
    }).catch((error) = > {
      console.log(error)  // failed
    })
Copy the code

【 7 】 Promise. Resolve ()

Sometimes you need to turn an existing object into a Promise object. The promise.resolve () method does this.

Promise.resolve('foo'New Promise(resolve => resolve();'foo'))Copy the code

[8] Promise. Reject ()

The promise.reject () method also returns a new Promise instance with a state of Rejected.

const p = Promise.reject('Wrong');
/ / is equivalent to
const p = new Promise((resolve, reject) = > reject('Wrong'))Copy the code

example

For example: you Promise to buy a bag for your wife when you make money this month, then you go to make money first, and when you make money, you immediately buy a bag for your wife. Keep your Promise and apologize immediately if you don’t make money. In code:

  // Buying a bag is a Promise. A Promise is a Promise
  // The husband makes a promise to his wife
  // In the coming month, I will give my wife a reply whether I earn money or not
  
  let buyBag = new Promise((resolve, reject) = > {
    // Promise accepts two arguments
    // resolve: call if asynchronous event succeeds (earn money)
    // reject: call when asynchronous event fails (no money earned)

    // Simulate the probability of making money event
    let result = function makeMoney() {
      return Math.random() > 0.5 ? 'Earn money' : 'Didn't make any money'
    }

    // The husband promises to give his wife an answer whether he earns money or not
    if (result == 'Earn money')
      resolve('I bought the bag.')
    else
      reject('Sorry, I didn't make any money this month')
  })


  buyBag().then(res= > {
    // Return "I bought a bag"
    console.log(res)
  }).catch(err= > {
    // Return "Sorry, I didn't make any money this month"
    console.log(err)
  })Copy the code

explain

The first paragraph calls the Promise constructor, and the second paragraph calls the. Then method of the Promise instance

1. Construct an example

  • The constructor takes a function as an argument
  • When the constructor is called to get the instance buyBag, the function as an argument is executed immediately
  • The argument function takes two callback arguments, resolve and reject
  • During the execution of the parameter function, calling ‘resolve’ will change the state of buyBag to ‘pity’, or calling ‘Reject’ will change the state of buyBag to ‘Rejected’

2. Call. Then

  • Call. Then to register two state callback functions for instance buyBag
  • This will trigger the execution of the first callback function when the state of the instance buyBag is fulfilled
  • When the status of the instance buyBag is Rejected, the second callback function is triggered


The article is updated every week. You can search “Front-end highlights” on wechat to read it in the first time, and reply to [Books] to get 200G video materials and 30 PDF books