Promise object
- Promise is a solution to asynchronous programming that makes more sense and is more powerful than the traditional solutions of callback functions and events.
- The so-called
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 you can retrieve messages for asynchronous operations. Promise provides a unified API so that all asynchronous operations can be handled in the same way. -
The Promise object has two characteristics.
(1) The state of the object is not affected by the outside world. A Promise object represents an asynchronous operation that has three states: Pending, Fulfilled, and Rejected. Only the result of an asynchronous operation can determine the current state, which cannot be changed by any other operation. That’s where the name Promise comes from, meaning “Promise” in English, meaning nothing can be changed by other means.
(2) Once the state changes, it doesn’t change again, and you can get this at any time. There are only two possibilities for the state of a Promise object to change: from pending to fulfilled and from pending to rejected. And when both of those things happen, the state is frozen and will never change again, and will remain the same, and that’s when it’s called resolved.
1. Examples of using callback functions
- The motion of a block
<! 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, Initial -scale=1.0"> </title> </head> </head>. 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 attributes for the element after applying the active stylesheet and parsing any basic calculations that these values might contain. 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])// let dis = (target-start)/ Math.abs(target-start) // dis > 1 let speed = dis * 4; Function fn() {let now = ParseInt (Window. GetComputedStyle (ele,null)[arg]) if(now == Target) {CB && CB (" Motion complete "); }else { ele.style[arg] = now + speed + 'px' setTimeout(fn, 50) } } fn(); } // Callback move(ele,"left",200,function(res){// Move console.log(res); Move (ele,"top",200,function(res){// Move to console.log(res); Move (ele,"left",0,function(res){// Move console.log(res); Move (ele, "top", 0) / / upward movement})})}) < / script > < / body > < / HTML >
2. Basic usage
ES6 states that the Promise object is a constructor that generates Promise instances.
The following code creates an instance of a Promise.
const promise = new Promise(function(resolve, reject) { // ... Some code if (/* Aasync */){resolve(value); } else { reject(error); }});
The Promise constructor takes as an argument a function that takes resolve and reject. These are two functions that are provided by the JavaScript engine rather than deployed yourself.
Resolve function is used, will Promise the state of an object from “pending” to “success” (that is, from pending to resolved), call when asynchronous operation is successful, and will be the result of the asynchronous operation, passed as a parameter; The reject function changes the state of a Promise object from “pending” to “failed” (that is, from pending to rejected), which is called when the asynchronous operation fails, and passes the error reported by the asynchronous operation as an argument.
3, Promise. Then ()
Promise instances have then methods, that is, then methods are defined on the prototype object Promise. Prototype. Its purpose is to add a callback function to the Promise instance when the state changes. As mentioned earlier, the first argument to the Then method is the callback to the Resolved state, and the second argument is the callback to the Rejected state, both of which are optional.
Once the Promise instance is generated, you can use the Then method to specify callbacks for the Resolved and Rejected states, respectively.
promise.then(function(value) {
// success
}, function(error) {
// failure
});
// Promise object pending (pending), flufilled(successful), Let p = new Promise(function(resolve,reject) {resolve("success"); reject("err"); }) console.log(p); // The then method takes two callback functions as arguments, Reject. Then (function(res){console.log(" successful callback ",res)},function(err){console.log(" failed callback ",err)){console.log(" failed callback ",err); })
The Promise is executed as soon as it is created.
let promise = new Promise(function(resolve, reject) { console.log('Promise'); resolve(); }); promise.then(function() { console.log('resolved.'); }); console.log('Hi! '); // Promise // Hi! // resolved
In the code above, the Promise is executed as soon as it is created, so the Promise is printed first. Then, the callback function specified by the Then method will not be executed until all synchronization tasks in the current script have completed, so Resolved will be the final output.
- Here is an example of asynchronously loading an image.
function onloadImg1() { return new Promise(function (resolve, reject) { let img = new Image(); Img.onLoad = function () {resolve(" Load completed "); } 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); })
- Movement Promise modification of blocks
<! 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, Initial -scale=1.0"> </title> </head> </head>. 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 attributes for the element after applying the active stylesheet and parsing any basic calculations that these values might contain. 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 (" complete ")} 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>
4, Promise. Finally ()
The finally() method is used to specify the action that will be performed regardless of the final state of the Promise object. This method is a standard introduced by ES2018.
Promise. Then (result = > {...}). The catch (error = > {...}), finally (() = > {...});
In this code, regardless of the Promise’s final state, the finally method callback is executed after the then or catch callback is executed.
5. Write a Promise
5-1 Promise declaration
Promise
Object is a constructor used to generatePromise
Instance.- Due to the
new Promise((resolve, reject)=>{})
, so pass in an argument (function) executor, and execute it. - Executor takes two arguments, one called resolve (success) and one called reject (failure).
- Since resolve and reject are executable
Class Promise {// constructor(executor) {// Let resolve = () => {} // Let rejtect = () => {} // Execute now executor(resolve, reject); }}
5-2 resolves the state of the Promise
- There are three states:
pending
(in progress),fulfilled
(has been successful) andrejected
(has failed). - On success, it cannot be transferred to another state, and there must be an unchangeable value.
- In case of failure, there must be an unchangeable reason.
new Promise((resolve, reject)=>{resolve(value)})
It will be fulfilled for success, and the parameter value is accepted. The state change is fulfilled, which cannot be changed again.new Promise((resolve, reject)=>{reject(reason)})
Reject reject reject reject reject reject reject reject reject reject-
Reject () if executor returns an error;
Class Promise {// constructor(executor) {this.state = 'pending'; this.value = undefined; Let resolve = (value) => {if (this.state = 'pending') {// Resolve to resolve (value) => {if (this.state = 'pending') {// Resolve to resolve (value) = 'pending') { This. value = value}} let rejtect = (reason) => {if (reason) => {if (reason) => {if (reason) => {if (reason) => {if (reason) (this.state = 'pending') {this.state = 'rejected'; this.state = 'rejected'; Try {// Executor (resolve, reject); } catch (err) { rejtect(err) } } }
5-3 then method
then
The first argument to the method isonFulfilled
State, the second argument isonRejected
State callback functions, both of which are optional. Success has the value of success, failure has the cause of failure- When the state is fulfilled, onFulfilled, pass in this. Value. OnRejected: Do not refute the rejected state unless you have rejected it
- Fulfilling and OnRejected If they are functions, they must be called after Fulfilling and Rejected respectively. Value or reason will be the first parameter of them in turn
Class Promise {// constructor(executor) {this.state = 'pending'; this.value = undefined; Let resolve = (value) => {if (this.state = 'pending') {// Resolve to resolve (value) => {if (this.state = 'pending') {// Resolve to resolve (value) = 'pending') { This. value = value}} let rejtect = (reason) => {if (reason) => {if (reason) => {if (reason) => {if (reason) => {if (reason) (this.state = 'pending') {this.state = 'rejected'; this.state = 'rejected'; Try {// Executor (resolve, reject); } Fulfilled {Fulfilled {Fulfilled}} Then (OnFilled, OnRejected) {If (This. State == 'Fulfilled ') {Fulfilled; Fulfilling (this. Value)} if (this.state == 'rejected') {Fulfilling (this. OnRejected (this.reason)}}
5-4 addresses asynchronous implementations
Since a Promise can have more than one Then, it is stored in the same array.
Let p = new Promise(); p.then(); p.then();
- Foreach calls them on success or failure
Class Promise {// constructor(executor) {this.state = 'pending'; this.value = undefined; This.reason = undefined; This. onResolvedArr = []; // store the failed array this. onrejectedArr = []; Let resolve = (value) => {if (this.state = 'pending') {// let resolve = (value) => {if (this.state = 'pending') { This. state = 'flufilled'; this.state = 'flufilled'; // Once reslove is executed, Calls to the success of this array. OnResolvedArr. ForEach (fn = > fn ())}} / / failed callback let rejtect = (reason) = > {the if (this. State = 'pending') {/ / State = 'rejected' this.state = 'rejected' this.state = 'rejected' this.state = 'rejected' this.state = 'rejected' Once a / / reject implemented, call fails an array of enclosing onRejectedArr. ForEach (fn = > fn ())}}; Try {// Executor (resolve, reject); } Fulfilled {Fulfilled {Fulfilled}} Then (OnFilled, OnRejected) {If (This. State == 'Fulfilled ') {Fulfilled; Fulfilling (this. Value)} if (this.state == 'rejected') {Fulfilling (this. If (this.state == 'pending') {this.onresolvedar.push (() => {this.onresolvedar.push (()) => {this.onresolvedar.push (()) => {this.onresolvedar.push (()) => {this.onresolvedar.push (()); onFlufilled(this.value) }) this.onRejectedArr.push(() => { onRejected(this.reason) }) } } }
5-5 resolves chained calls
We use it all the timenew Promise().then().then()
This is the chained call to solve the callback hell
1. For chaining, we default to return a Promise in the first Then. Promise2 = new promise ((resolve, reject)=>{}) promise2 = new promise ((resolve, reject)=>{})
- The value returned by this promise2 is passed to the next then
- If an ordinary value is returned, the ordinary value is passed to the next then
2. When we return a parameter in the first then, we return a parameter in the first then. This return results in a new promise that is the value of onFulfilled() or onRejected()
The value of onFulfilled() or onRejected(), which is the value returned by the first then, is called x. The function that determines x is called resolvePromise
- First, check if x is a promise.
- If it is a Promise, then the result is assumed to be the success of the new promise2
- If it is a normal value, it is directly the result of succeeding as promise2
- So it’s X versus promise2
- The resolvePromise parameter is promise2 (the default promise returned), x (ourselves)
return
‘, ‘resolve’, ‘reject’ - Resolve and reject is promise2
Class Promise {// constructor(executor) {this.state = 'pending'; this.value = undefined; This.reason = undefined; This. onResolvedArr = []; // store the failed array this. onrejectedArr = []; Let resolve = (value) => {if (this.state = 'pending') {// let resolve = (value) => {if (this.state = 'pending') { This. state = 'flufilled'; this.state = 'flufilled'; // Once reslove is executed, Calls to the success of this array. OnResolvedArr. ForEach (fn = > fn ())}} / / failed callback let rejtect = (reason) = > {the if (this. State = 'pending') {/ / State = 'rejected' this.state = 'rejected' this.state = 'rejected' this.state = 'rejected' this.state = 'rejected' Once a / / reject implemented, call fails an array of enclosing onRejectedArr. ForEach (fn = > fn ())}}; Try {// Executor (resolve, reject); } catch (err) { rejtect(err) } } then(onFlufilled, onRejected) { let promise2 = new Promise((resolve, Reject) => {if (this. State == 'Fulfilled ') {// Fulfilled for this. // resolvePromise (promise2, promise2, promise2, promise2, promise2, promise2); Fulfilling (promise2, x, resolve, reject)} if (this.state == 'rejected') {Fulfilling (promise2, x, resolve, reject)} OnRejected (this.reason); let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, Reject)} if (this.state == 'pending') {this. onresolvedar.push (() = bb0 {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) }) } }) return promise2; }}
5-6 Complete the ResolvePromise function
The different Promise codes are interchangeable, called resolvePromise
- If x === promise2, then this will cause a circular reference and wait for it to complete, then this will result in a ‘circular reference’ error
let p = new Promise(resolve => { resolve(0); }); Var p2 = p.then(data =>) {return p2; })
1, judge x
- Otherwise, if x is an object or function,Let then be x.then
- X cannot be null
- Resolve (x) to resolve(x)
- X is an object or function (including a promise),
let then = x.then
When X is an object or function (default Promise) - The statement then
- Reject () if then is an error
- If then is a function, then is executed with call, with the first argument this, followed by a successful and unsuccessful callback
- If the successful callback is still a PORMISE, then recursion will continue to parse. If the successful callback is still a PORMISE, then recurse
function resolvePromise(promise2, x, resolve, Reject){if(x === promise2){// reject return reject(new TypeError('Chaining cycle detected for promise')); } // prevent multiple calls to let called; // If (x!) is not null and x is an object or function if (x! = = = = null && (typeof x 'object' | | typeof x = = = 'function')) {try {/ / A + rules, method statement then = x then let then = x.t hen; // If then is a function, If (typeof then === 'function') {// let the then execute the first argument (this) followed by a successful callback and a failed callback (x). Y => {// Success and Failure can only call one if (called) return; called = true; Promise2 (promise2, y, resolve, reject); promise2 (promise2, y, resolve, reject); }, err => {// Success and failure can only call one if (called) return; called = true; reject(err); })} else {resolve(x); }} catch (e) {if (called) return; called = true; Reject (e); reject(e); reject(e); } } else { resolve(x); }}
5-7 Solve other problems
Onfulfilled, OnRejected are all optional parameters, if they are not functions, they must be ignored
- Onfulfilled returns an ordinary value, which is equal to directly on success
value => value
- OnRejected returns a normal value. If it fails, it will be moved to the onFulfilled in the next then. Therefore, it will throw an error
reason => throw err
2,secretSpecifies that onFulfilled or onRejected cannot be called synchronously and must be called asynchronously. So let’s use setTimeout to solve the asynchronous problem - If the onFulfillment or onRejected error is reported, reject() will be returned.
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); This is very depressing. It can be fulfilled for you. It can be fulfilled for you. Value onFulfilled = typeof onFulfilled === 'function'? onFulfilled : value => value; // Unless you have rejected something unless it is a function unless it is a function unless it is a function unless it is a function unless it is a function unless it is a function unless it is a function unless it is a function unless it is a function unless it is a function unless it is a function unless it is a function unless it is a function unless onRejected : err => { throw err }; let promise2 = new Promise((resolve, Fulfilling (this. State === 'Fulfilling ') {// Fulfilling (this. State ===' Fulfilling ') {// Fulfilling (this. resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); }}, 0); }; If (this. State = = = 'rejected') {/ / asynchronous setTimeout () = > {/ / if error try {let x = onRejected (enclosing a tiny); 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 (enclosing a tiny); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); }}}, 0)); }; }); // return promise2 (promise2); }}