The promise of an asynchronous js solution
1. Promise definition
Promise is a solution to asynchronous programming that makes more sense and is more powerful than traditional solutions — callback functions and events.
reference
- Promisra + Usage specifications
To understand:
- Without asynchrony, promises are not needed.
- Promises aren’t asynchronous per se, just a way for us to write asynchronous code
2. Promise specifications
When Es6 incorporated promises into its specification, it followed A corresponding standard – the Promise A+ specification.
It is summarized as specification 4321
4:4 Big terms 3:3 states 2:2 events 1:1 objects
2.1 Four Terms
-
Fulfill (fulfill) : a set of operations such as state changes and callback execution that occur when a promise succeeds. Although fulfill is adopted as fulfill, resolve is adopted as fulfill in later generations.
-
Reject: A sequence of actions that occurs when a promise fails.
-
Eventual Value: The so-called final value refers to the value transferred to the solution callback when the promise is solved. Since the promise has the characteristics of one-off, when this value is passed, it marks the end of the promise waiting state, so it is called the final value, sometimes directly referred to as value.
-
Reason: The rejection reason, the value passed to the rejection callback when a promise is rejected.
2.2 Three states
- Pending state
- This is a big pity.
- (Rejected)
When a promise is in the wait state, it must meet the following conditions:
- You can migrate to the execute or reject state
This is a big pity.
In the execution state, a promise must satisfy the following conditions:
- You cannot migrate to any other state
- You must have an immutable end value
(Rejected)
In the rejection state, a promise must satisfy the following conditions:
- You cannot migrate to any other state
- There must be an immutable cause
2.3 Two types of events
For the three states, there are only the following two conversion directions:
- Pending – > fulfilled
- Pendeing – > the rejected
When the state transitions, events are emitted.
If it is Pending — > Fulfiied, onFulFilled event will be triggered. If it is Pendeing — > Rejected, onFulFilled event will be triggered
2.4 One Object
This is a promise object
3. Basic use of promise
3.1 Basic Usage
let p = new Promise(function (resolve,reject) {
reject("no");
})
console.log('p :', p);
Copy the code
The two arguments in the callback function are used to transition the state:
Resolve, select state from PENDING — > fullFilled Reject, select state from Pending — > Rejected
3.2 then method
When the state transitions, events are emitted
.
Ondepressing event will be triggered if it is pending — > FulfiIED
If it is Pendeing — > Rejected, the onRejected event is triggered
For registration of events, the Promise object provides then methods, as follows:
3.3 Typical definition of Promise
3.3.1 Case 1: Reading files
const fs = require("fs");
let p = new Promise(function (resolve,reject) {
fs.readFile("03 - based/js a.t xt." "."utf8",(err,date)=>{
if(err){
reject(err);
}else{ resolve(date); }}); }); p.then(result= >{
console.log('result :', result);
}).catch(err= >{
console.log('err :', err);
});
Copy the code
3.3.2 Case 2: Return results based on random numbers
let p = new Promise((resolve,reject) = >{
setTimeout((a)= >{
let num = Math.random();
if(num>0.5){
resolve("success");
}else{
reject("fail"); }},1000);
});
p.then(result= >{
console.log('result :', result);
},err=>{
console.log('err :', err);
})
Copy the code
3.3.3 Reading File Encapsulation
const fs = require("fs");
function readFile(file){
return new Promise((resolve,reject) = >{
fs.readFile("file"."utf8",(err,date)=>{
if(err){
reject(err);
}else{ resolve(date); }}); }); } readFile("a.txt").then(result= >{
console.log('result :', result);
},err=>{
console.log('err :', err);
})
Copy the code
3.4 All and race methods
-Leonard: All the races
Both All and Race are static methods of the Promise constructor object. Call directly with Promise as follows:
- Promise. All ()
- Promise. Reace ()
- The return value is zero
promise
Object.
- The return value is zero
When you have multiple asynchronous operations, you often have two requirements :(somewhat similar to the logic and logic or in operators)
-
Ensure that all asynchronous operations are complete before an operation, if only one failure, do not proceed
-
Whenever there is an asynchronous operation article, an operation is performed in it.
Use all as follows
If there are any errors, see below
The use of the fax
4. Use a third-party Promise library
For third-party Promise libraries, there are two well-known libraries:
- bluebird
- q.js
Take Bluebird as an example to demonstrate its usage on the server side.
The first step is installation
Step two, use
4. Write the most complete version of the Promise Principle
I can enter the more hierarchical learning principle in Github. I have gradually encapsulated the basic version promise, the upgraded version promise and the complete version promise in Github.
Making address: github.com/quyuandong/…
The sample
The source code
// Define the state of the current promise
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ / promise object
class Promise {
constructor(exector) {
// Initialize status to wait state
this.status = PENDING;
// Success value
this.value = undefined;
// Cause of failure
this.reason = undefined;
// Store the successful callback function
this.onResolvedCallbacks = [];
// Store the failed callback function
this.onRejectedCallbacks = [];
// Successful handler function
let resolve = (value) = > {
if (this.status == PENDING) {
this.value = value; // Store successful values
this.status = RESOLVED; // Change the current status to success
this.onResolvedCallbacks.forEach(fn= > fn())
}
}
// Failed handler
let reject = (reason) = > {
if (this.status == PENDING) {
this.reason = reason; // Cause of storage failure
this.status = REJECTED; // Change the current state to failed state
this.onRejectedCallbacks.forEach(fn= > fn())
}
}
// When Pormise throws an exception
try {
exector(resolve, reject) // Execute the function immediately
} catch (e) {
reject(e)
}
}
/** * parameter: * @param {*} onFulfilled fulfilled ** @param {*} onFulfilled fulfilled This is a big promise, which may be fulfilled with onRejected. This is a big promise, which can be fulfilled all the time. Then, I need to return a promise * onFulfilled and onRejected. Its state is taken * if it is normal, this value is taken as the result of the success of the next THEN * */
then(onFulfilled, onRejected) {
P.teng ().then().then().then()...
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
onRejected = typeof onRejected === 'function' ? onRejected : err= > { throw err };
/** * Create a promise and return a promise, so that the setTimeout function can be used to obtain the promise2 * try function: handle ondepressing which may throw an exception */
let promise2 = new Promise((resolve, reject) = > {
------- synchronous operation (no asynchronous code in the executor)
if (this.status == RESOLVED) {
setTimeout((a)= > {
try {
let x = onFulfilled(this.value);// x can be a promise or a normal value
// If x is a promise(with its own state), we need to make pormise2 have the same state as x
resolvePromise(promise2, x, resolve, reject); // Handle the relationship between promise2 and x
} catch (e) {
reject(e)
}
}, 0);
}
------- synchronous operation (no asynchronous code in the executor)
if (this.status === REJECTED) {
setTimeout((a)= > {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)}// Wait state, save successful and failed operations ------- synchronous operation (asynchronous code in actuator)
if (this.status === PENDING) {
this.onResolvedCallbacks.push((a)= > {
setTimeout((a)= > {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)});this.onRejectedCallbacks.push((a)= > {
setTimeout((a)= > {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)})}})returnpromise2; }}/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Handle the relationship between promise2 and X, which is the return value of onFulfilled or onRejected
function resolvePromise(promise2, x, resolve, reject) {
// if x === promise2, a circular reference is created and waits for completion
if (promise2 === x) {
return reject(new TypeError('my Chaining cycle detected for promise'))}// Prevent multiple calls
let called;
// x is an object (not null) or a function
if(x ! = =null && (typeof x === "object" || typeof x === "function")) {
try {
// It is possible that x will be manually added with a then attribute
let then = x.then;
if (typeof then === 'function') { // x is a promise
// equivalent to x.teng (y=>{},r=>{})
then.call(x, y => {
if (called) return;
called = true;
// Return a promise
resolvePromise(promise2, y, resolve, reject)
}, r => {
if (called) return;
called = true;
// Use promise to pass down failed results
reject(r)
})
} else { // if x is an object, it returns an object
resolve(x)
}
} catch (e) { // When x throws an exception
if (called) return;
reject(e)
}
} else { //x is an ordinary value
resolve(x)
}
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// resolve static method
Promise.resolve = function (val) {
return new Promise((resolve, reject) = > {
resolve(val)
});
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// reject static methods
Promise.resolve = function (val) {
return new Promise((resolve, reject) = > {
reject(val)
});
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// race static method
Promise.race = function (promises) {
return new Promise((resolve, reject) = > {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject)
}
});
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// all (get all promises, execute then, place the results in an array, and return them together)
Promise.all = function (promises) {
let arr = [];
let y = 0;
function processData(index, data) {
arr[i] = data;
y++;
if (y == promises.length) {
return arr;
};
};
return new Promise((resolve, reject) = > {
for (let i = 0; i < promises.length; i++) {
promises[i].then(data= > {
processData(i, data)
}, reject)
}
})
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
//
/** * To verify that promises are true, add the following code: /** * To verify that promises are true: /** * To verify that promises are true, add the following code: /** * To verify that promises are true: /** * Promises -aplus-tests [js file name] */
// Currently it is through his tests that he will test an object
/ / syntactic sugar
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve,reject) = >{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Export a promise
module.exports = Promise;
/** * Note: When asynchracy occurs in a promise, the successful and failed callback functions for then must be saved first, and then executed when the state in the promise changes
Copy the code