This is the 6th day of my participation in the August Better Writing Challenge.
preface
Promise is familiar to all of us, and is used more or less in work or study. It is a solution to asynchronous programming that is more reasonable and powerful than traditional solutions (callback functions and events). Previously asynchronous programming, handled by callback functions, would have been Mired in an endless callback hell – one callback nested within another, and so on and so forth.
Here’s an example:
// assume that $ajax is an asynchronous event, success is a callback function, and the next request depends on the result of the previous request. success: function () { $ajax({ // ... success: function () { $ajax({ // ... success: function () { // ... }}); }}); }});Copy the code
Create a Promise_
Let’s start by creating a Promise object. To distinguish it from a real Promise, we’ll call it Promise_. As you all know, creating a Promise object requires passing in a function that takes two inputs: resolve and reject.
Let’s start with a class:
class Promise_ { constructor(callback) { // 1. Check whether the input parameter is the function if (! (callback instanceof Function)) { console.error(`Promise resolver ${callback} is not a function`); return; }}}Copy the code
Let’s think about resolve and reject again.
The Promise implementation is essentially a publish-subscribe model. Callbacks are passed in to methods like then, catch, and finally, all of which are subscribers and are stored in the subscriber list inside a Promise. The resolve or Reject calls loop through the list of subscribers, publishing subscriptions.
Based on this principle, we need to maintain two subscriber lists inside Promise_, each storing the two callback functions passed in by the THEN method.
So now our Promise_ :
class Promise_ { status = "pedding"; // this is a pity; // status: pedding someday rejected successDep = []; ErrorDep = []; errorDep = []; ResultVal = undefined; Constructor (callback) {// 1. Check whether the input parameter is the function if (! (callback instanceof Function)) { console.error(`Promise resolver ${callback} is not a function`); return; }}}Copy the code
Resolve and reject
Let’s implement resolve and reject again. The basic idea of these two methods is to change the internal state of the Promise object, which is fulfilled and Rejected, respectively, and execute the list of callback functions passed in by the THEN method.
class Promise_ { status = "pedding"; // this is a pity; // status: pedding someday rejected successDep = []; ErrorDep = []; errorDep = []; ResultVal = undefined; Constructor (callback) {// 1. Check whether the input parameter is the function if (! (callback instanceof Function)) { console.error(`Promise resolver ${callback} is not a function`); return; } callback(this.resolve, this.reject); // notify notify resolve => {// set this. Status = "depressing "; this.resultVal = value; This.successdep.foreach ((m) => {m(value); }); }; Reject = (value) => {// assign this. Status = "reject "; this.resultVal = value; Errordep. forEach((m) => {m(value); }); }; }Copy the code
then
Publish the subscription method is implemented, let’s implement the subscription method. The then method takes two arguments, both of which are functions. The first argument to the THEN method is the callback function of the Fulfilled state and the second argument is the callback function of the Rejected state, both of which are optional.
// Instanceof Function then = (success, error) => { success : () => {}; error = error instanceof Function ? error : () => {}; // Judge status if (this. Status == "depressing ") {success(this. return this; } if (this.status === "rejected") { error(this.resultVal); return this; } // Add a subscriber this.successdep.push (success); this.errorDep.push(error); // return this; };Copy the code
Now that a basic Promise_ class is implemented, we can verify that it works:
const p = new Promise_((res, rej) => { setTimeout(() => { rej(233); }, 300); }); P.teng ((val) => {console.log("resolve: ", val); }, (err) => {console.log("reject: ", err); });Copy the code
Print:
catch
The catch method is an alias for the THEN method and is used to specify the callback function when an error occurs. If an asynchronous operation throws an error, the status changes to Rejected, and the callback specified by the catch method is called to handle the error. In addition, the then method specifies a callback that is caught by the catch method if it throws an error during execution.
Implementation:
class Promise_ { status = "pedding"; // this is a pity; // status: pedding someday rejected successDep = []; ErrorDep = []; errorDep = []; ResultVal = undefined; Constructor (callback) {// 1. Check whether the input parameter is the function if (! (callback instanceof Function)) { console.error(`Promise resolver ${callback} is not a function`); return; } try { callback(this.resolve, this.reject); } catch (error) { this.reject(error); This is a big pity; // notify release resolve = (value) => {// set this. Status = "pity "; this.resultVal = value; This.successdep.foreach ((m) => {try {m(value); } catch (error) { this.reject(error); }}); }; Reject = (value) => {// assign this. Status = "reject "; this.resultVal = value; Errordep. forEach((m) => {m(value); }); }; // Instanceof Function then = (success, error) => { success : () => {}; error = error instanceof Function ? error : () => {}; // Judge status if (this. Status == "depressing ") {success(this. return this; } if (this.status === "rejected") { error(this.resultVal); return this; } // Add a subscriber this.successdep.push (success); this.errorDep.push(error); // return this; }; Catch = (error) => {// Check whether the input parameters are all functions error = error instanceof Function? error : () => {}; if (this.status === "rejected") { error(this.resultVal); return this; } // Add a subscriber this.errordep.push (error); // return this; }; }Copy the code
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. Regardless of the final state of the promise, the callback specified by the finally method is executed after the callback specified by then or catch is executed.
Implementation:
finally = (cb) => {
return this.then(
() => cb(),
() => cb()
);
};
Copy the code
Promise_.all
The promise. all method is used to wrap multiple Promise instances into a new Promise instance. The promise. all method takes an array as an argument.
const p = Promise.all([p1, p2, p3]);
Copy the code
- When the states of the incoming array Promise members become
fulfilled
.p
Will becomefulfilled
At this time,p1
,p2
,p3
To form an array of return values passed top
The callback function of. - When one of the array Promise members is passed in
rejected
.p
The state of theta becomes thetarejected
At this time, the first to bereject
Is passed top
The callback function of.
Implementation:
Static all = (arr) => {static all = (arr) => { (arr instanceof Array)) { console.error(`Promise resolver ${arr} is not a Array`); return; If (arr.length === 0) return new Promise_((res) => res([])); return new Promise_((res, rej) => { let resArr = []; let num = 0; for (let i = 0; i < arr.length; i++) { let p = null; // Check if array member is Promise_ object if (! (arr[i] instanceof Promise_)) { p = Promise_.resolve(arr[i]); } else { p = arr[i]; } p.then((val) => { resArr[i] = val; if (++num === arr.length) { res(resArr); } }).catch((err) => { rej([err]); }); }}); }; Static resolve = (val) => {return new Promise_((res, rej) => {res(val); }); };Copy the code
Promise_.race
The promise.race method also wraps multiple Promise instances into a new Promise instance.
const p = Promise.all([p1, p2, p3]);
Copy the code
If one instance of P1, P2, and P3 changes state first, then the state of P changes. The return value of the first changed Promise instance is passed to p’s callback.
Implementation:
Static race = (arr) => {// Check whether the input is an array if (! (arr instanceof Array)) { console.error(`Promise resolver ${arr} is not a Array`); return; If (arr.length === 0) return new Promise_((res) => res([])); return new Promise_((res, rej) => { let f = false; for (let i = 0; i < arr.length; i++) { let p = null; // Check if array member is Promise_ object if (! (arr[i] instanceof Promise_)) { p = Promise_.resolve(arr[i]); } else { p = arr[i]; } p.then((val) => { if (f) return; f = true; res(val); }).catch((err) => { if (f) return; f = true; rej(err); }); }}); };Copy the code
Promise_.any
ES2021 introduces the promise.any method. The method takes a set of Promise instances as parameters and returns them wrapped as a new Promise instance.
As long as one parameter instance becomes a depressing state, the packaging instance will become a depressing state. If all parameter instances become the Rejected state, the wrapper instance becomes the Rejected state.
Implementation:
Static any = (arr) => {static any = (arr) => { (arr instanceof Array)) { console.error(`Promise resolver ${arr} is not a Array`); return; If (arr.length === 0) return new Promise_((res) => res([])); return new Promise_((res, rej) => { let num = 0; let f = false; for (let i = 0; i < arr.length; i++) { let p = null; // Check if array member is Promise_ object if (! (arr[i] instanceof Promise_)) { p = Promise_.resolve(arr[i]); } else { p = arr[i]; } p.then((val) => { if (f) return; f = true; res(val); }).catch((err) => { if (f) return; if (++num === arr.length) { rej(new Error("any error")); }}); }}); };Copy the code
A complete instance
Now that you’ve basically completed the Promise class, post the full version of the code:
class Promise_ { status = "pedding"; // this is a pity; // status: pedding someday rejected successDep = []; ErrorDep = []; errorDep = []; ResultVal = undefined; Constructor (callback) {// 1. Check whether the input parameter is the function if (! (callback instanceof Function)) { console.error(`Promise resolver ${callback} is not a function`); return; } try { callback(this.resolve, this.reject); } catch (error) { this.reject(error); Static all = (arr) => {static all = (arr) => { (arr instanceof Array)) { console.error(`Promise resolver ${arr} is not a Array`); return; If (arr.length === 0) return new Promise_((res) => res([])); return new Promise_((res, rej) => { let resArr = []; let num = 0; for (let i = 0; i < arr.length; i++) { let p = null; // Check if array member is Promise_ object if (! (arr[i] instanceof Promise_)) { p = Promise_.resolve(arr[i]); } else { p = arr[i]; } p.then((val) => { resArr[i] = val; if (++num === arr.length) { res(resArr); } }).catch((err) => { rej([err]); }); }}); }; Static race = (arr) => {// Check whether the input is an array if (! (arr instanceof Array)) { console.error(`Promise resolver ${arr} is not a Array`); return; If (arr.length === 0) return new Promise_((res) => res([])); return new Promise_((res, rej) => { let f = false; for (let i = 0; i < arr.length; i++) { let p = null; // Check if array member is Promise_ object if (! (arr[i] instanceof Promise_)) { p = Promise_.resolve(arr[i]); } else { p = arr[i]; } p.then((val) => { if (f) return; f = true; res(val); }).catch((err) => { if (f) return; f = true; rej(err); }); }}); }; Static any = (arr) => {static any = (arr) => { (arr instanceof Array)) { console.error(`Promise resolver ${arr} is not a Array`); return; If (arr.length === 0) return new Promise_((res) => res([])); return new Promise_((res, rej) => { let num = 0; let f = false; for (let i = 0; i < arr.length; i++) { let p = null; // Check if array member is Promise_ object if (! (arr[i] instanceof Promise_)) { p = Promise_.resolve(arr[i]); } else { p = arr[i]; } p.then((val) => { if (f) return; f = true; res(val); }).catch((err) => { if (f) return; if (++num === arr.length) { rej(new Error("any error")); }}); }}); }; Static resolve = (val) => {return new Promise_((res, rej) => {res(val); }); }; // notify release resolve = (value) => {// set this. Status = "depressing "; this.resultVal = value; This.successdep.foreach ((m) => {try {m(value); } catch (error) { this.reject(error); }}); }; Reject = (value) => {// assign this. Status = "reject "; this.resultVal = value; Errordep. forEach((m) => {m(value); }); }; // Instanceof Function then = (success, error) => { success : () => {}; error = error instanceof Function ? error : () => {}; // Judge status if (this. Status == "depressing ") {success(this. return this; } if (this.status === "rejected") { error(this.resultVal); return this; } // Add a subscriber this.successdep.push (success); this.errorDep.push(error); // return this; }; Catch = (error) => {// Check whether the input parameters are all functions error = error instanceof Function? error : () => {}; if (this.status === "rejected") { error(this.resultVal); return this; } // Add a subscriber this.errordep.push (error); // return this; }; finally = (cb) => { return this.then( () => cb(), () => cb() ); }; }Copy the code
conclusion
Promise is very important for front-end development and will be used at work or in interviews. How do you get into Promise? It must have been a handwritten Promise. This article implements a simplified version of Promise, which basically has everything you need.
If after reading this article, if it is helpful to you, please click on it and pay attention to it. I wish you a happy life.