preface

As we all know, one of the biggest features of Javascript is that its language execution environment is single-threaded, meaning that only one task can be completed at a time. This means that all tasks need to be queued, one task executed before the next. The seemingly simple execution mode may be delayed due to the long execution time of one task, thus affecting the execution of the whole program

Synchronous and asynchronous

To better address the single-threaded nature of Javascript, the task is executed in two modes: Synchronous and Asynchronous

Synchronous mode programming

The synchronous mode is mentioned in the preface. All tasks are arranged and executed one by one, and the execution order is consistent with the task arrangement order

Console. log(' task 1') for (let I = 0; i < 10; I++) {console.log(' task 2')} console.log(' task 3'); (function(){console.log(' task 4')}())Copy the code

Asynchronous programming

The most basic way to accomplish asynchronous programming is to define pure callback functions, which have one or more callback functions in a task

Common asynchronous code: timers, event binding, Ajax…

; (function() {console.log(' task 1, perform immediately ') setTimeout(function() {console.log(' task 1-2, perform immediately ') 5 seconds later ')}, 5000)}()) console.log(' Task 2', 'later ')Copy the code

As an asynchronous operation, subsequent tasks are not blocked due to asynchronous operations. The execution sequence in asynchronous mode is different from that in synchronous mode

Problems with asynchronous programming

For cascading HTTP requests, complex business scenarios, or to optimize computationally long operations, it is not impossible to concatenate multiple asynchronous operations. Have you ever seen multiple nested callbacks to solve a problem

getDepartment('', ({success, data}) => { if (success) { // .... getStaffsByDepartmentId(data[0].id, ({success, data}) => { if (success) { //... getTrainDetail(data[0].id, ({success, data}) => { if (success) { // ... }})}})Copy the code

The name callback hell comes from the fact that as code is stretched to the right and nested, it is not extensible and nested code is mixed with complex business logic that is extremely difficult to maintain

Promise came into being

Fortunately, I have not experienced the nightmare of callback hell. With unpredictable execution times and results, using promises is more powerful than traditional, multi-layered nested callback functions, because no one wants to get too deep

What is the Promise

As you can see from ECMAScript 6 introduction, Promises are a solution to asynchronous programming. It was first proposed and implemented by the community and written into the language standard in ES6

Simply put, promises are an object that encapsulates an asynchronous operation and can retrieve its results and state, a solution to asynchronous programming

Basic use of Promise

Generate a Promise instance

  1. Promise is a constructor that creates a Promise instance with the new operator

  2. This constructor takes a function as an argument, which we commonly call an executor function

  3. The executor function takes two arguments: these arguments are callable as functions and can be passed in data, usually named resolve and reject

    • The first parameterResolve: Callback function after asynchronous operation is successfully executed
    • Second parameterReject: Callback function when an asynchronous operation fails
const promise = new Promise((resolve, Reject) => {// executable // Async operation setTimeout(() => {const rand = math.random () * 100 // Simulate success or failure if (rand >= 50) {// Execute on success Resolve ()} else {reject()}}, 1000)})Copy the code

The state of the Promise

Promise instances have three states

  • Pending (In progress, initial state)
  • This is a big pity :(sometimes called resolved)
  • My rejected.

There are only two possibilities for a state change:

  • Pending to resolved
  • Pending a rejected

The state of a Promise instance is private, and can be transferred only through executor functions. Resolve and Reject are called within the executor functions to control the state change. The actuator throws an exception, which can change the pending state to Rejected. No matter whether the state changes from Pending to Resolved or Rejected, as long as the state of the Promise instance changes, the state is already fixed and irreversible and will not change in the future

New Promise((resolve, reject) => {}) This is a big pity (forget) => resolve()) // this is a big pity (forget) Reject) => reject()) // Reject () new Promise((resolve, reject) => {throw new Error(' Error ')}) // Reject () => reject(Copy the code

The resolve function does the following

Change the state of the Promise instance from Pending to Resolved, call it when the asynchronous operation succeeds, and pass the result of the asynchronous operation as a parameter

Reject function

Change the state of the Promise instance from Pending to Rejected, call it when the asynchronous operation fails, and pass the error reported by the asynchronous operation as a parameter.

Then method

The Promise prototype object has the THEN method, which is the primary method that specifies a handler for the Promise instance. The Promise instance can be called directly. The THEN method takes two optional parameters (onResolved handler, onRejected handler), This method returns a new Promise instance

  • Provide the first parameter onResolved handler:resolvedState callback function
  • Provide a second argument to the onRejected handler:rejectedState callback function
const promise = new Promise((resolve, Reject) => {setTimeout(() => {const rand = math.random () * 100 if (rand >= 50) { 'James', age: 36})} else {reject(new Error('Error'))}}, 1000)}) promise.then((value) => {console.log(' error ', value)}, (error) => {// Console. log(' failed ', error)}) when the state of the promise instance is RejectedCopy the code

Because the state of the Promise instance changes, there is only one result, passing in two handlers that either change their state to Resolved and onResolved, or their state changes to Rejected and onRejected. Of course, if the state is always pending, neither of these handlers will execute

About optional parameters

Both arguments to the then method are optional. See Javascript Advanced Programming. Any arguments that are not of a function type are silently ignored, for example: If you want to provide only the onRejected argument, pass null or undefined in the onResolved argument. This helps avoid creating redundant objects in memory

Promise. then(null, (error) => {console.log(' console.log ', error)})Copy the code
Promise. then((value) => {console.log(' error ', value)})Copy the code

About chain calls

As mentioned earlier, the THEN method eventually returns a new Promise instance, so you can make chain calls that express asynchronous actions as a flow of synchronous actions, avoiding layers of nested callback functions

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve({name: 'James', age: 36})
  }, 1000)
})

promise.then(
  (value) => {
    console.log('onResolved1', value)
    return value
  },
).then(
  (value) => {
    console.log('onResolved2', value)
    return value
  },
).then(
  (value) => {
    console.log('onResolved3', value)
    return value
  }
)
Copy the code

About state values and result values

  • The new Promise instance has a state value of Rejected, and the result value is the exception thrown
  • An arbitrary value that is not a PROMISE is returned in the handler. The new PROMISE instance has a status value of Resolved and the result value is the return value
  • A new promise (promise.resolve, promise.reject) is manually returned from the handler, and the result of this promise is the result of the new promise

Catch method

The Promise prototype object has a catch method that specifies a failure (rejection) handler for the Promise instance, equivalent to a. Then (NULL, (error) => {}) syntactic sugar

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error('error'))
  }, 1000)
})

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

Replace the second argument of the then method with the catch method

The second optional argument to the THEN method (the onRejected handler) is called when the Promise instance is in the Rejected state. With the catch method, we can handle exceptions by omitting the second argument to the then method

// bad
Promise.then(
  (value) => { // ... },
  (error) => { // ... }
).then(
  (value) => { // ... },
  (error) => { // ... }
)

// good
Promise
  .then((value) => { // ... })
  .then((value) => { // ... })
  .catch((error) => { // ... })
Copy the code

Any error thrown by either of them will be caught by the last catch(),

Other apis for Promise

In the basic use of Promise, we introduced the THEN and catch methods on the Promise prototype object. Here we introduce other Promise apis

Promise.resolve

Resolve is a static method of Promise. Previously, we knew that calling the Promise constructor with new could generate a Promise instance. The initial state of the Promise instance is pending, and changing the state of the Promise instance can only be done within the executor. Calling promise.resolve () returns a Promise instance with a state of resolve

New Promise((resolve) => resolve())Copy the code

Non-promise instances as parameters

Promise.resolve({name: 'James'}) // Promise {<fulfilled>: {name: 'James'}

Promise.resolve('Hello Promise') // Promise {<fulfilled>: 'Hello Promise'}

Promise.resolve() // Promise {<fulfilled>: undefined}

Promise.resolve(new Error('error')) // Promise {<fulfilled>: Error: error
Copy the code

Promise. The resolve method passes in any non-Promise instances and returns a Promise instance with a state of Resolved

The Promise instance is taken as an argument

const p1 = new Promise((resolve, reject) => resolve({name: 'James', age: 36})) const p2 = Promise.resolve({name: 'Curry', age: 33}) promise.resolve (p1) // p1 instance promise.resolve (p2) // P2 instanceCopy the code

If the argument is a Promise instance, promise.resolve will return the instance unchanged

Promise.reject

Promise. Reject is similar to Promise. Resolve as a static method. Calling promise.reject () returns an instance of Promise in a reject state

Promise. Reject () // equivalent to new Promise(resolve, reject) => reject())Copy the code

Error catch about promise.reject

A Promise. Reject error cannot be caught by try/catch

try {
  Promise.reject('Error')
} catch (error) {
  console.log('catch', error)
}
// Uncaught (in promise) Error
Copy the code

Exceptions are handled through the promise.catch method

Promise.reject('Error').catch((error) => {
  console.log('catch', error) // catch Error
})
Copy the code

Promise.all

Promise.all This static method, used to process multiple Promise instances, receives an iterable, and eventually returns a new Promise instance

const p1 = new Promise((resolve, reject) => resolve({name: 'James', age: 36}))
const p2 = Promise.resolve({name: 'Curry', age: 33})

Promise.all([p1, p2])
  .then((value) => {
    console.log(value) // [{name: 'James', age: 36}, {name: 'Curry', age: 33}]
  })
  .catch((error) => {
    console.log(error)
  })
Copy the code

We passed in two Promise instances with resolved states and returned a new Promise instance with resolved state. The result is an array returned in iterator order

Influence of status values

  • Contains an instance of a Promise whose state value is Pending
const p1 = new Promise((resolve, reject) => {})
const p2 = new Promise((resolve, reject) => resolve({name: 'James', age: 36}))
const p3 = Promise.resolve({name: 'Curry', age: 33})

const promise = Promise.all([p1, p2, p3])

setTimeout(() => {
  console.log(promise) // Promise {<pending>}
}, 1000)
Copy the code
  • The state values of all promise instances are resolved.
const p1 = new Promise((resolve, reject) => resolve({name: 'James', age: 36}))
const p2 = Promise.resolve({name: 'Curry', age: 33})

const promise = Promise.all([p1, p2])

setTimeout(() => {
  console.log(promise) // Promise {<fulfilled>: Array(2)}
}, 1000)
Copy the code
  • Contains a Promise instance with a state value of Rejected
const p1 = new Promise((resolve, reject) => reject())
const p2 = new Promise((resolve, reject) => resolve({name: 'James', age: 36}))
const p3 = Promise.resolve({name: 'Curry', age: 33})

const promise = Promise.all([p1, p2, p3])

setTimeout(() => {
  console.log(promise) // Promise {<rejected>: undefined}
}, 1000)
Copy the code

The state of all incoming promise instances is Resolved, and the state of the new returned Promise instance is Resolved. If the incoming promise instance state contains pending or Rejected, The state value of the newly returned Promise instance is either Pending or Rejected

Promise.race

Promise.race This static method takes an iterable and ultimately returns a new Promise instance, unlike promise.all, where no matter what state the Promise instance is passed in, Promise.race will ultimately require only the first Promise instance whose state has changed and return a new Promise instance

const p1 = new Promise((resolve) => {})
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve({name: 'James', age: 36})
  }, 1000)
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('error')
  }, 2000)
})

const promise = Promise.race([p1, p2, p3])
  .then((value) => {
    console.log('onResolved', value) // onResolved {name: 'James', age: 36}
  })
  .catch((error) => {
    console.log('onRejected', error)
  })
Copy the code

Write in the last

The above is my Promise in the application of some simple understanding, I hope you see a lot of support, if there is a place to write description is not clear, also please forgive me and give advice 😁