First understand the concept of the following concepts:
Synchronization: Only one task can be executed at a time. After this task is completed, the next task can be executed, which blocks other tasks.
Asynchronous: Multiple tasks can be performed together.
Callback hell: The nesting of callback functions, resulting in too many layers of code that are difficult to understand and maintain.
I. The meaning of Promise
Let’s take a look at the following Promise meanings and features:
-
Promise is a solution for asynchronous programming that is more reasonable and powerful than traditional solutions (callback functions and events);
-
A Promise is simply a container that holds the result of an event (usually an asynchronous operation) that will end in the future.
-
Syntactically, a Promise is an object from which to get messages for asynchronous operations;
-
The Promise object represents an asynchronous operation with three states: Pending, fulfilled and Rejected. This is a pity.
Features of Promise objects:
1. The status of the object is not affected by the outside world.
Only the result of an asynchronous operation can determine which state is currently in, and no other operation can change that state.
2. Once the state changes, it will never change.
There are only two possibilities for a Promise object to change state:
- Change from Pending to depressing
- From pengding to Rejected
As soon as these two states are discovered the state is fixed and will not change and will remain as it is called resolved
3. Each Promise instance has a THEN method.
4. Each time a Promise is executed, a new Promise instance is returned;
With the Promise object, you can express asynchronous operations as a flow of synchronous operations, eliminating the problem of asynchronous layers of nested functions (callback hell for short).
When it comes to promises, the first thing that comes to mind is asynchronous chain calls.
Disadvantages of Promise objects:
-
Unable to cancel the Promise. Once created it will be executed immediately, can not be cancelled midway;
-
If you don’t set a callback function, the Promise throws an error internally and doesn’t react externally;
-
When in the Pending state, there is no way to know which node is currently progressing (just started or about to complete).
Advantages of using Promise objects:
- Can solve the asynchronous nesting problem (callback hell);
- Can solve multiple asynchronous concurrency problems;
Two, basic usage
Note that in order to facilitate the writing, the “resolved” in this chapter only refers to the regrettable state, excluding the rejected state.
1. Create a Promise instance
ES6 specifies that a Promise object is a constructor that uses new to generate a Promise instance.
let promise = new Promise(() = > {// Executor executor, which is characterized by immediate execution
})
Copy the code
This Promise instance is a class that allows you to take a function as an argument, called an Executor executor, which is typically executed immediately. The following will be printed immediately:
let promise = new Promise(() = > {//executor executor, which executes immediately
console.log("Immediate execution");//Promise has three states. The default state is Pending
})
console.log("222");
/* Console prints */
// Execute immediately
/ / 222
Copy the code
2. Resolve,rejected; then
The function accepts two parameters, resolve and Rejected, and each Promise instance has one
Then method. (Note: Resolve and Rejected must be used together with THEN.)
Then places two functions:
- Onfulfils the logic to be performed successfully by an example
- The onRejected instance fails the logic to be executed
let promise = new Promise((resolve,rejected) = > {
resolve('success');// If resolve is called, then will succeed;
}).then(data= > {/ / success
console.log(data);
},err= > {/ / fail
console.log(err);
})
/* Console prints */
/ / success
let promise = new Promise((resolve,rejected) = > {
rejected('failure');// If (rejected) then (rejected) then (rejected)
}).then(data= > {/ / success
console.log(data);
},err= > {/ / fail
console.log(err);
})
/ / fail
// The code above can also be written like this:
let promise = new Promise((resolve, rejected) = > {
resolve('success');
})
promise.then(data= > {
console.log(data);
}, err= > {
console.log(err);
})
Copy the code
The state of a Promise instance does not change once the state changes, so resolve and Rejected will not take effect. And vice versa.
let promise = new Promise((resolve,rejected) = > {
resolve('success');
rejected('failure');// This step will not be executed
}).then(data= > {/ / success
console.log(data);
},err= > {/ / fail
console.log(err);
})
/ / success
Copy the code
If the Promise instance reports an internal error, it becomes a failed state and does not execute the following method:
let promise = new Promise((resolve, rejected) = > {//executor executor, which executes immediately
throw new Error('Internal throw error');// If an error is thrown internally, then the state becomes failed
resolve('success');// This step will not be executed
}).then(data= > {/ / success
console.log(data);
}, err= > {/ / fail
console.log(err);
})
//Error: An internal Error is thrown
// ...
Copy the code
Principle of Promise instance
Write a basic Promise by hand
Create a promise. Js, create a promise class, and export:
//promise.js:
class Promise {};module.exports = Promise;/ / export
Copy the code
Introduce the previous code into promise.js:
/ / callBack. Js:
let Promise = require('./promise');
// Introduce a custom Promise. The following Promise is a custom Promise
let promise = new Promise((resolve, rejected) = > {
resolve('success');
}).then(data= > {
console.log(data);
}, err= > {
console.log(err);
})
Copy the code
Define a base version of the Promise from the callback.js Promise instance, without considering other exceptions:
(1) Create public THEN methods
A Promise instance has three states, and the THEN methods will be executed in either state, so the THEN methods are a common property.
//promise.js:
class Promise {
then(){}};module.exports = Promise;/ / export
Copy the code
Each Promise instance has its own three states, so put them into the corresponding constructor.
The state of the Promise instance is available in the constructor, and since these three states are used frequently, we can store them as a constant.
//promise.js:
const PENDING = "PENDING";// Wait state
const RESOLVED = "RESOLVED";// Success status
const REJECTED = "REJECTED";// Failed state
class Promise {
constructor(){// constructor
this.status = PENDING;// The default pending state of the Promise instance
}
then(){}};module.exports = Promise;/ / export
Copy the code
We pass a function (i.e., an executor) in the new Promise instance of callbacks.js, and this function executes immediately, so we pass an executor executor to the constructor as well:
//promise.js:
const PENDING = "PENDING";// Wait state
const RESOLVED = "RESOLVED";// Success status
const REJECTED = "REJECTED";// Failed state
class Promise {
constructor(executor){// constructor
this.status = PENDING;// The default pending state of the Promise instance
executor();// The default executor executes immediately
}
then(){}};module.exports = Promise;/ / export
Copy the code
When the executor executes a new Promise instance of callbacks.js, it passes two functions that belong to the current Promise instance and need not be retrieved from then, so we can declare two functions from constructor: a success function and a failure function. And pass both functions to the executor executor:
//promise.js:
const PENDING = "PENDING";// Wait state
const RESOLVED = "RESOLVED";// Success status
const REJECTED = "REJECTED";// Failed state
class Promise {
constructor(executor){// constructor
this.status = PENDING;// The default pending state of the Promise instance
// Success function
let resolve = () = >{}// Fail function
let reject = () = > {
}
executor(resolve,reject);// The default executor executes immediately
}
then(){}};module.exports = Promise;/ / export
Copy the code
Both successful and failed functions accept a value, value and Reason, because these values are also used in THEN, so we need to define a variable. We need to update the state of the Promise after executing the success and failure functions:
//promise.js:
const PENDING = "PENDING";// Wait state
const RESOLVED = "RESOLVED";// Success status
const REJECTED = "REJECTED";// Failed state
class Promise {
constructor(executor){// constructor
this.status = PENDING;// The default pending state of the Promise instance
this.value = undefined;// Success value
this.reason = undefined;// Cause of failure
// Success function
let resolve = (value) = > {
this.value = value;
this.status = RESOLVED;// The Promise instance status is updated to successful: Resolved
}
// Fail function
let reject = (reason) = > {
this.reason = reason;
this.status = REJECTED;// The STATE of the Promise instance changes to the Failed state: Rejected state
}
executor(resolve,reject);// The default executor executes immediately
}
then(){}};module.exports = Promise;/ / export
Copy the code
Since the state of a Promise instance cannot be changed again once it has changed, that is to say, we cannot call resolve, reject, so we must add state judgment, and execute the function only when the state is waiting for state pending:
//promise.js:
const PENDING = "PENDING";// Wait state
const RESOLVED = "RESOLVED";// Success status
const REJECTED = "REJECTED";// Failed state
class Promise {
constructor(executor){// constructor
this.status = PENDING;// The default pending state of the Promise instance
this.value = undefined;// Success value
this.reason = undefined;// Cause of failure
// Success function
let resolve = (value) = > {
if(this.status === PENDING){//// shield call, call a successful function cannot call a failed function
this.value = value;
this.status = RESOLVED;// After the call succeeds, the Promise state becomes Resolved}}// Fail function
let reject = (reason) = > {
if(this.status === PENDING){
this.reason = reason;
this.status = REJECTED;After //// fails, the Promise state changes to the Rejected state
}
}
executor(resolve,reject);// The default executor executes immediately
}
then(){}};module.exports = Promise;/ / export
Copy the code
An exception may be thrown during execution, so add a try… The catch function, which calls reject if an exception is thrown internally:
Next we call the then() method, which can place two functions:
- Onfulfils the logic to be performed successfully by an example
- The onRejected instance fails the logic to be executed
So which method is called when? This depends on the state of the Promise instance:
Promise instances also have subscription publishing capabilities:
To be continued, follow-up updates ~~
Promise.js complete code:
//promise.js:
const PENDING = "PENDING";// Wait state
const RESOLVED = "RESOLVED";// Success status
const REJECTED = "REJECTED";// Failed state
class Promise {
constructor(executor){// constructor
this.status = PENDING;// The default pending state of the Promise instance
this.value = undefined;// Success value
this.reason = undefined;// Cause of failure
this.onResolveCallBacks = [];// Array of successful callbacks
this.onRejectCallBacks = [];// Array of failed callbacks
// Success function
let resolve = (value) = > {
if(this.status === PENDING){//// shield call, call a successful function cannot call a failed function
this.value = value;
this.status = RESOLVED;// After the call succeeds, the Promise state becomes Resolved
this.onResolveCallBacks.forEach(fn= > fn())/ / release}}// Fail function
let reject = (reason) = > {
if(this.status === PENDING){
this.reason = reason;
this.status = REJECTED;After //// fails, the Promise state changes to the Rejected state
this.onRejectCallBacks.forEach(fn= > fn())/ / release}}// An internal error may occur when the actuator executes:
try{
executor(resolve,reject);// The default executor executes immediately, taking resolve,reject as arguments
}catch(error){
reject(error);// If an error occurs during the execution of the actuator, it is equivalent to calling the failed method}}then(onfulfilled,onrejected){/// Then currently has two parameters: onfulfilled, onRejected
// Synchronization condition: execute logic after success
if(this.status === RESOLVED){
onfulfilled(this.value);
}
// Synchronization: execute logic after failure
if(this.status === PENDING){
onrejected(this.reason);
}
// If it is asynchronous, subscribe first
if (this.status === PEDING) {
this.onResolveCallBacks.push(() = > {
// todo
onfulfilled(this.value)
})
this.onRejectCallBacks.push(() = > {
// todo
onrejected(this.value)
})
}
}
};
module.exports = Promise;/ / export
Copy the code
A. Promise B. Promise C. Promise D. Promise
1, implement function sleep, first print A, 1 second later print B, what is the solution?
(1) Achieve through Promise:
console.log('A');
function sleep(time) {
return new Promise((resolve) = > {
setTimeout(() = >{ resolve(); }, time); })}; sleep(1000).then(() = > {
console.log('B');
});
// Output A first, then output B after A delay of 1 second
/ / or
console.log('A');
const sleep = ((time) = >{
return new Promise((resolve) = >{
setTimeout(() = >{
resolve();
},time)
})
})
sleep(1000).then(() = >{
console.log('B');
})
Copy the code
(2) Implemented through Async/AWIAT:
const sleep = ((time) = >{
return new Promise((resolve) = >{
setTimeout(() = >{
resolve();
},time)
})
})
async function sleepAsync(){
await sleep(1000);
console.log('B');
}
Copy the code
(3) Implement from Generator and yield
console.log("A");
const sleep = ((time) = >{
return new Promise((resolive) = >{
setTimeout(() = >{
resolve();
},time)
})
})
function* sleepGenerator(time){
yeild sleep(time);
}
sleepGenerator(1000).next().value.then(() = >{
console.log("B");
})
Copy the code
Similar interview questions:
There are often business requirements that require you to wait a few seconds before taking the next step
2, the red light three seconds once, the green light one second, yellow light two seconds once; How do I make three lights turn on again and again? (Promse + recursion)
Three lighting functions already exist:
Ideas:
Three seconds on a red light, green light for a second time, yellow light 2 seconds on time, which means that for 3 seconds, performs a function of red, 2 seconds, perform a green function, 1 second to perform a yellow function, alternating repeated lights, which means that in this order has been executed this three functions, this step can use recursion to achieve.
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
const sleep = ((time,fn) = >{
return new Promise((resolve) = >{
setTimeout(() = >{
fn();// Which light is on
resolve();
},time)
})
})
let step = (() = >{
Promise.resolve().then(() = >{
return sleep(3000,red);
}).then(() = >{
return sleep(2000,green);
}).then(() = >{
return sleep(1000,yellow);
}).then(() = >{ step(); })})Copy the code
3. Output the following execution result:
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
/ / input 1
Copy the code
The Promise. Resolve method returns a new Promise object in the resolved state, if the parameter is a raw value or an object that does not have then methods. The arguments to the promise. resolve method are also passed to the callback function.
The then method takes a function as an argument, and if it passes something other than a function, it actually interprets it as THEN (NULL), which causes the result of the previous Promise to penetrate below.
Application scenarios of Promise
.
In learning writing, continue to supplement and update, record bad places hope to point out modification, common progress ~
References:
ECMAScript 6 Getting Started – Promises
Interview questions about Promise
Handwritten Promise20 line
Analyze the internal structure of Promise, step by step to achieve a complete Promise class that can pass all Test cases
Write a Promise