Promise object
-
Promise is a solution to asynchronous programming that makes more sense and is more 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. Promise provides a uniform API, and all kinds of asynchronous operations can be handled in the same way.
-
Promise objects have two characteristics.
(1) The state of the object is not affected by the outside world. The Promise object represents an asynchronous operation with three states: Pending, fulfilled and Rejected. Only the result of an asynchronous operation can determine the current state, and no other operation can change the state. That’s where the name “Promise” comes from. Its English name means “Promise,” indicating that nothing else can change it.
(2) Once the state changes, it will never change again, and this result can be obtained at any time. There are only two possibilities for the state of the Promise object to change from pending to depressing and from pending to Rejected. As long as these two things are happening the state is fixed, it’s not going to change, it’s going to stay the same and that’s called resolved.
Examples of how to use the callback function
- Motion of the cube
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, < span style>. Box {height: 100px; width: 100px; position: absolute; left: 0; top: 0; background-color: aqua; } < / style > < div class = "box" > < / div > < body > < script > / / the window. The getComputedStyleWindow. GetComputedStyle () method returns an object, This object reports the values of all CSS properties of the element after the active stylesheet is applied and any basic calculations that those values may contain are parsed. let ele = document.querySelector(".box") let el = window.getComputedStyle(ele,null)["height"] function Move (ele,arg,target,cb) {let start = parseInt(window.getcomputedStyle (ele,null)[arg] Math. Abs (target-start) // let speed = dis * 4; Function fn() {let now = parseInt(window.getcomputedStyle (ele,null)[arg]) if(now == target) {cb&&cb(" 新 完 全 ") }else { ele.style[arg] = now + speed + 'px' setTimeout(fn, 50) } } fn(); } // move(ele,"left",200,function(res){// move right over console.log(res); Move (ele,"top",200,function(res){// move down console.log(res); Move (ele,"left",0,function(res){// move console.log(res); Move (ele, "top", 0) / / upward movement})})}) < / script > < / body > < / HTML >Copy the code
2. Basic usage
ES6 specifies that a Promise object is a constructor that generates a Promise instance.
The following code creates an instance of Promise.
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* Asynchronous operation succeeded */){
resolve(value);
} else{ reject(error); }});Copy the code
The Promise constructor takes a function as an argument, resolve and reject. They are two functions that are provided by the JavaScript engine and do not need to be deployed themselves.
The resolve function changes the state of the Promise object from “unfinished” to “successful.” It will be called when the asynchronous operation succeeds and will pass the result of the asynchronous operation as an argument. The Reject function changes the state of the Promise object from “unfinished” to “failed” (i.e., from Pending to Rejected). It is called when the asynchronous operation fails and passes the error reported by the asynchronous operation as a parameter.
3, Promise. Then ()
Promise instances have THEN methods, that is, then methods defined on the prototype object Promise.Prototype. It adds a callback function to the Promise instance when the state changes. As mentioned earlier, the first argument to the THEN method is the resolved state callback and the second argument is the Rejected state callback, both of which are optional.
After the Promise instance is generated, you can use the THEN method to specify the resolved and Rejected state callback functions, respectively.
promise.then(function(value) {
// success
}, function(error) {
// failure
});
Copy the code
// The Promise object is pending, flufilled(succeeded), rejected (failed).
let p = new Promise(function(resolve,reject) {
resolve("success");
reject("err");
})
console.log(p);
The then method takes as arguments two callback functions, resolve on success and Reject on failure
p.then(function(res){
console.log("Successful callback",res)
},function(err){
console.log("Failed callback",err)
})
Copy the code
Promises are implemented as soon as they are created.
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('resolved.');
});
console.log('Hi! ');
// Promise
// Hi!
// resolved
Copy the code
In the code above, the Promise is executed immediately after it is created, so the Promise is printed first. Then, the callback specified by the then method will not execute until all synchronization tasks in the current script have finished, so resolved will output.
- Here is an example of loading images asynchronously.
function onloadImg1() {
return new Promise(function (resolve, reject) {
let img = new Image();
img.onload = function () {
resolve("Load complete");
}
img.onerror = function () {
reject("Load failed");
}
img.src='https://gimg2.baidu.com/image_search/src=http%3A%2F%2F1812.img.pp.sohu.com.cn%2Fimages%2Fblog%2F2009%2F11%2F18%2F18%2F8 %2F125b6560a6ag214.jpg'
})
}
onloadImg1().then(res= > {
console.log(res);
}, err= > {
console.log(err);
})
Copy the code
- Block motion Promise transformation
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, < span style>. Box {height: 100px; width: 100px; position: absolute; left: 0; top: 0; background-color: aqua; } < / style > < div class = "box" > < / div > < body > < script > / / the window. The getComputedStyleWindow. GetComputedStyle () method returns an object, This object reports the values of all CSS properties of the element after the active stylesheet is applied and any basic calculations that those values may contain are parsed. let ele = document.querySelector(".box") let el = window.getComputedStyle(ele, null)["height"] function move(ele, arg, target) { return new Promise((resolve, reject) => { let start = parseInt(window.getComputedStyle(ele, null)[arg]) let dis = (target - start) / Math.abs(target - start) let speed = dis * 5; function fn() { let now = parseInt(window.getComputedStyle(ele, Null)[arg]) if (now == target) {// cb && cb(" finish ")} else {ele. Style [arg] = now + speed + 'px' setTimeout(fn, 50) } } fn(); }) } move(ele, "left", 200).then(res => { console.log(res); return move(ele, "top", 200) }).then(res => { return move(ele, "left", 0) console.log(res); }).then(res => { return move(ele, "top", 0) console.log(res); }).then(res => { console.log(res); }) </script> </body> </html>Copy the code
4, Promise. Finally ()
The finally() method is used to specify actions that will be performed regardless of the final state of the Promise object. This method was introduced as a standard in ES2018.
promise
.then(result= >{...}). The catch (error= >{...}). Finally,() = > {···});
Copy the code
In the code above, regardless of the last state of the promise, the callback specified by the finally method is executed after the callback specified by then or catch.
Write promises by hand
5-1 Statement of the Promise
-
The Promise object is a constructor that generates a Promise instance.
-
Since new Promise((resolve, reject)=>{}), an argument (function) executor is passed in and executed.
-
Executor takes two arguments, resolve and reject.
-
Resolve and reject are executable
class Promise {
/ / the constructor
constructor(executor) {
// Callback on success
let resolve = () = > {}
// Callback on failure
let rejtect = () = > {}
// Execute immediatelyexecutor(resolve, reject); }}Copy the code
5-2 Resolve the Promise state
-
There are three states: pending, fulfilled and rejected. This is a pity.
-
On success, it cannot go to another state and must have an immutable value.
-
When a failure occurs, it cannot be changed to another state, and there must be an immutable reason.
-
New Promise((resolve, reject)=>{resolve(value)}) resolve is successful, and the parameter value is accepted. The state changes to a pity, which cannot be changed again.
-
New Promise((resolve, reject)=>{reject(reason)}) Reject indicates the reject parameter. Reject indicates the reject parameter.
-
If the executor function fails, execute reject().
class Promise { / / the constructor constructor(executor) { // Initial state this.state = 'pending' // Success value this.value = undefined; // Failure cause this.reason = undefined // Callback on success let resolve = (value) = > { if (this.state = 'pending') { // State changes to a successful state after the resolve call this.state = 'flufilled' // Store the value of value this.value = value } } // Callback on failure let rejtect = (reason) = > { if (this.state = 'pending') { // State changes to a failed state after the resolve call this.state = 'rejected' // Store the reason for reason this.reason = reason } }; try { // Execute immediately executor(resolve, reject); } catch (err) { rejtect(err) } } } Copy the code
5-3 then method
then
The first argument to the method isonFulfilled
The second argument to the state callback function isonRejected
State callback functions, which are optional. Success has the value of success, failure has the cause of failure- When the state is depressing, ondepressing will be executed and this.value will be passed. If the state is rejected, execute onRejected and pass this.reason
- OnFulfilled,onRejected If they are functions, they must be called after the fulfilled,onRejected, respectively, and value or reason must be their first parameter in turn
class Promise {
/ / the constructor
constructor(executor) {
// Initial state
this.state = 'pending'
// Success value
this.value = undefined;
// Failure cause
this.reason = undefined
// Callback on success
let resolve = (value) = > {
if (this.state = 'pending') {
// State changes to a successful state after the resolve call
this.state = 'flufilled'
// Store the value of value
this.value = value
}
}
// Callback on failure
let rejtect = (reason) = > {
if (this.state = 'pending') {
// State changes to a failed state after the resolve call
this.state = 'rejected'
// Store the reason for reason
this.reason = reason
}
};
try {
// Execute immediately
executor(resolve, reject);
} catch (err) {
rejtect(err)
}
}
then(onFlufilled, onRejected) {
if (this.state == 'fulfilled') {
// Perform ondepressing and pass in the successful value
onFlufilled(this.value)
}
if (this.state == 'rejected') {
// This is a big pity. Execute onRejected and pass in the failed value
onRejected(this.reason)
}
}
}
Copy the code
5-4 Address asynchronous implementations
Because a promise can have more than one THEN, it exists in the same array.
// Multiple THEN cases
let p = new Promise(a); p.then(); p.then();Copy the code
- ForEach calls them on success or failure
class Promise {
/ / the constructor
constructor(executor) {
// Initial state
this.state = 'pending'
// Success value
this.value = undefined;
// Failure cause
this.reason = undefined;
// Store the successful array
this.onResolvedArr = [];
// Store the failed array
this.onRejectedArr = [];
// Callback on success
let resolve = (value) = > {
if (this.state = 'pending') {
// State changes to a successful state after the resolve call
this.state = 'flufilled'
// Store the value of value
this.value = value;
// Once reslove is executed, the array is successfully called
this.onResolvedArr.forEach(fn= > fn())
}
}
// Callback on failure
let rejtect = (reason) = > {
if (this.state = 'pending') {
// State changes to a failed state after the resolve call
this.state = 'rejected'
// Store the reason for reason
this.reason = reason;
// Once reject executes, the array that failed is called
this.onRejectedArr.forEach(fn= > fn())
}
};
try {
// Execute immediately
executor(resolve, reject);
} catch (err) {
rejtect(err)
}
}
then(onFlufilled, onRejected) {
if (this.state == 'fulfilled') {
// Perform ondepressing and pass in the successful value
onFlufilled(this.value)
}
if (this.state == 'rejected') {
// This is a big pity. Execute onRejected and pass in the failed value
onRejected(this.reason)
}
// State is pending
if (this.state == 'pending') {
this.onResolvedArr.push(() = > {
onFlufilled(this.value)
})
this.onRejectedArr.push(() = > {
onRejected(this.reason)
})
}
}
}
Copy the code
5-5 solve the chain call
We use it all the timenew Promise().then().then()
This is the chain call to solve callback hell
1. To achieve the chain, we return a promise in the first THEN by default. Promise2 = new promise (resolve, reject)=>{})
- Pass the value returned by this promise2 into the next THEN
- If a normal value is returned, the normal value is passed to the next THEN
2. If we return a parameter in the first then. This new promise that comes out of return is onFulfilled() or onRejected()
The value of onFulfilled() or onRejected(), which is the value returned by the first THEN, is called X. The function to judge X is called resolvePromise
- First of all, let’s see if x is a promise.
- If it is a promise, take its outcome as the outcome of the new promise2 success
- If the value is normal, it is used as the result of the success of promise2
- So compare X to promise2
- ResolvePromise parameters are promisE2 (the promise returned by default), x (ourselves)
return
Object, resolve, reject - Resolve and Reject are promise2
class Promise {
/ / the constructor
constructor(executor) {
// Initial state
this.state = 'pending'
// Success value
this.value = undefined;
// Failure cause
this.reason = undefined;
// Store the successful array
this.onResolvedArr = [];
// Store the failed array
this.onRejectedArr = [];
// Callback on success
let resolve = (value) = > {
if (this.state = 'pending') {
// State changes to a successful state after the resolve call
this.state = 'flufilled'
// Store the value of value
this.value = value;
// Once reslove is executed, the array is successfully called
this.onResolvedArr.forEach(fn= > fn())
}
}
// Callback on failure
let rejtect = (reason) = > {
if (this.state = 'pending') {
// State changes to a failed state after the resolve call
this.state = 'rejected'
// Store the reason for reason
this.reason = reason;
// Once reject executes, the array that failed is called
this.onRejectedArr.forEach(fn= > fn())
}
};
try {
// Execute immediately
executor(resolve, reject);
} catch (err) {
rejtect(err)
}
}
then(onFlufilled, onRejected) {
let promise2 = new Promise((resolve, reject) = > {
if (this.state == 'fulfilled') {
// Perform ondepressing and pass in the successful value
onFlufilled(this.value);
// the resolvePromise function handles the relationship between its return promise and the default promise2
let x = onFlufilled(this.value);
resolvePromise(promise2, x, resolve, reject)
}
if (this.state == 'rejected') {
// This is a big pity. Execute onRejected and pass in the failed value
onRejected(this.reason);
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
}
// State is pending
if (this.state == 'pending') {
this.onResolvedArr.push(() = > {
onFlufilled(this.value);
let x = onFlufilled(this.value);
resolvePromise(promise2, x, resolve, reject)
})
this.onRejectedArr.push(() = > {
onRejected(this.reason);
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
})
}
})
returnpromise2; }}Copy the code
5-6 Complete the resolvePromise function
Making different promise codes work with each other is called resolvePromise
- If x === promise2, a circular reference is created and waits for completion. A circular reference error is reported
let p = new Promise(resolve= > {
resolve(0);
});
var p2 = p.then(data= > {
// Circular reference, waiting for their own completion, a lifetime
return p2;
})
Copy the code
1
- Otherwise, if x is an object or function,Let then be x.then
- X cannot be null
- X is a normal value. Resolve (x)
- X is an object or function (including promise),
let then = x.then
2. When x is an object or function (default promise) - The statement then
- Reject () if ‘then’ fails, reject()
- If then is a function, then is executed with call, taking this as the first argument, followed by a successful callback and a failed callback
- If the successful callback is still pormise, the recursion continues. 3. Success and failure can only be called one, so set a called to prevent multiple calls
function resolvePromise(promise2, x, resolve, reject){
// Loop reference error
if(x === promise2){
/ / reject an error
return reject(new TypeError('Chaining cycle detected for promise'));
}
// Prevent multiple calls
let called;
// x is not null and x is an object or function
if(x ! =null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+ specifies the then method that declares then = x
let then = x.then;
// If then is a function, the default is Promise
if (typeof then === 'function') {
// Let then execute the first argument this, followed by a successful callback and a failed callback
then.call(x, y= > {
// Only one can be called for success or failure
if (called) return;
called = true;
// the result of resolve is still a promise
resolvePromise(promise2, y, resolve, reject);
}, err= > {
// Only one can be called for success or failure
if (called) return;
called = true;
reject(err);// If you fail, you fail})}else {
resolve(x); // You can do just that}}catch (e) {
// Also a failure
if (called) return;
called = true;
// Then is not validreject(e); }}else{ resolve(x); }}Copy the code
5-7 Solve other problems
Ondepressing and onRejected are both optional parameters. If they are not functions, they must be ignored
- Ondepressing returns a normal value, which equals directly when successful
value => value
- OnFulfilled returns a common value. If value => value, then the onFulfilled will run into the next onFulfilled, so there will be a mistake
reason => throw err
2,secretOnFulfilled or onRejected cannot be called synchronously and must be called asynchronously. We’ll use setTimeout to solve the asynchronous problem - This is a pity or onFulfilled. If onFulfilled or onRejected fails, you can return reject().
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value= > {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn= >fn()); }};let reject = reason= > {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn= >fn()); }};try{
executor(resolve, reject);
} catch(err) { reject(err); }}then(onFulfilled,onRejected) {
// onFulfilled if this is not a function, ignore onFulfilled and return value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
// onRejected if it is not a function, just ignore onRejected and throw an error
onRejected = typeof onRejected === 'function' ? onRejected : err= > { throw err };
let promise2 = new Promise((resolve, reject) = > {
if (this.state === 'fulfilled') {
/ / asynchronous
setTimeout(() = > {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch(e) { reject(e); }},0);
};
if (this.state === 'rejected') {
/ / asynchronous
setTimeout(() = > {
// If an error is reported
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch(e) { reject(e); }},0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() = > {
/ / asynchronous
setTimeout(() = > {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch(e) { reject(e); }},0);
});
this.onRejectedCallbacks.push(() = > {
/ / asynchronous
setTimeout(() = > {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch(e) { reject(e); }},0)}); }; });// Return promise, complete the chain
returnpromise2; We can't help but use promises in our work to address asynchronous callbacks. Many libraries or plug-ins you use use promises such as Axios, FETCH, etc. But do you know how promise comes out? Here's the promisesA+ spec, which is cheap10I sold you the yuan.1,PromiseHandwritten statementPromiseLink: HTTPS://juejin.cn/post/6844903625769091079
Copy the code