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
-
Promise is a constructor that creates a Promise instance with the new operator
-
This constructor takes a function as an argument, which we commonly call an executor function
-
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 parameter
Resolve: Callback function after asynchronous operation is successfully executed
- Second parameter
Reject: Callback function when an asynchronous operation fails
- The first parameter
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:
resolved
State callback function - Provide a second argument to the onRejected handler:
rejected
State 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 😁