Many big companies like to make handwritten promises during interviews, so sometimes we have to program them for the interview.

To implement your own promise, let’s first look at the official promise usage. Here’s the code:

const foo = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve('111') }, 1000); }) } foo().then((res) => { console.log(res); }) console.log('hello'); // print '111' after 'hello'Copy the code

First, let’s comb through the idea according to this code:

  1. Let’s declare a class, let’s call it classMyPromise;
  2. MyPromiseThe class accepts a functionfnAs parameters, andfnThere are two parametersresolveandreject, are functions;
  3. defineMyPromiseThe three states of class,pending,fulfilledandrejected;
  4. MyPromiseOf the classconstructorTo execute a function infn,resolveandrejectPassed to thefn, the implementation ofresolveandrejectWhen to changeMyPromiseClass state;
  5. implementationthenMethod,thenThe method takes two functions as arguments;
  6. Implementation of chain call;

Let’s do it in code.

The first step:

Const PENDING = 'PENDING '; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; Class MyPromise {// Class properties can be defined directly at the top level status = PENDING; // Set pending result = undefined; // resolve result reason = undefined; Const resolve = (result) => {// Only pending state can be modified to a depressing state if (this.status === PENDING) {// Store the result and change the state this.result = result; this.status = FULFILLED; Reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {if (this.status === pending) { This. Reason = reason; this.status = REJECTED; }} // fn(resolve, reject); }}Copy the code

The constructor takes a function and executes it immediately. This is the basic process of a new operation.

The second step:

Const PENDING = 'PENDING '; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; Class MyPromise {// Class properties can be defined directly at the top level status = PENDING; // Set pending result = undefined; // resolve = undefined; Const resolve = (result) => {// Only pending state can be modified to a depressing state if (this.status === PENDING) {// Store the result and change the state this.result = result; this.status = FULFILLED; Reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {if (this.status === pending) { This. Reason = reason; this.status = REJECTED; }} // fn(resolve, reject); } // then(onResolve, onReject) {// If the state is fulfilled, execute onResolve, This. Status === depressing) {onResolve(this.result); If (this.status === reject) {onReject(this.reason)}} // Reject = reject (reject) {reject (this.reason)}Copy the code

The then method is simple. It takes two functions and executes them. The result and Reason arguments are the values passed in to resolve and reject.

At this time the basic function of MyPromise has been implemented (happy 😊), let’s try it out:

const foo = () => { return new MyPromise((resolve, reject) => { setTimeout(() => { resolve('111') }, 1000); }) } foo().then((res) => { console.log(res); }) console.log('hello'); / / output 'hello'Copy the code

Wait, that’s not right! Why only ‘hello’ and not ‘111’? 😱 😱 😱

Don’t panic. Let’s get the logic straight:

As you can see from the recent code snippet, resolve is executed with a setTimeout delay of 1 second, while then is executed synchronously before resolve. The state of MyPromise is still ‘pending’, so the onResolve method is not executed and ‘111’ is not printed.

Finding the reason, let’s modify the then method:

Const PENDING = 'PENDING '; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; Class MyPromise {// Class properties can be defined directly at the top level status = PENDING; // Set pending result = undefined; // resolve = undefined; OnResolveArr = []; // Save the first parameter onResolve to the THEN method, which will be fulfilled when the waiting state becomes depressing. onRejectArr = []; // store the second parameter of the then method, onReject, and wait until the state changes to Rejected. Const resolve = (result) => {// This. Status === = this PENDING) {// Store the result and change the state this.result = result; this.status = FULFILLED; This.onresolvearr.map (onResolve => onResolve())); Reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {if (this.status === pending) { This. Reason = reason; this.status = REJECTED; Reject(reject => onRejectarr.map); // Reject(reject => onReject()); }} // fn(resolve, reject); OnResolve (reject); onReject (reject); onReject (reject); If (this.status === PENDING) {// Since onResolve and onReject accept arguments, we push an anonymous function; this.onResolveArr.push(() => { onResolve(this.result); }) this.onRejectArr.push(() => { onReject(this.reason); This is a big pity; onResolve(this. Status === depressing) {onResolve(this. Result); If (this.status === reject) {onReject(this.reason)}} // Reject = reject (reject) {reject (this.reason)}Copy the code

[bug Mc-10894] – If the status of the then method is pending, store onResolve and onReject into an array for resolve and REJECT execution in the future.

At this point, the then method is basically implemented, and then executes the previous example, and finds that it normally returns ‘hello’ and ‘111’.

But! 😂😂😂 Cannot be chained, because the second then method does not return a value, so Cannot read properties of undefined.

Const PENDING = 'PENDING '; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; Class MyPromise {// Class properties can be defined directly at the top level status = PENDING; // Set pending result = undefined; // resolve = undefined; OnResolveArr = []; // Save the first parameter onResolve to the THEN method, which will be fulfilled when the waiting state becomes depressing. onRejectArr = []; // store the second parameter of the then method, onReject, and wait until the state changes to Rejected. Const resolve = (result) => {// This. Status === = this PENDING) {// Store the result and change the state this.result = result; this.status = FULFILLED; This.onresolvearr.map (onResolve => onResolve())); Reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {const reject = (reject) => {if (this.status === pending) { This. Reason = reason; this.status = REJECTED; Reject(reject => onRejectarr.map); // Reject(reject => onReject()); }} // fn(resolve, reject); } handleNewPromise(res, newPromise, resolve, Reject) {// If the first then function returns the current promise, A circular reference to if (res === newPromise) {return Reject (new TypeError('Chaining cycle detected for Promise '))} // prevents multiple calls to let called; / / if the object type or function type if (typeof res = = = 'object' | | typeof res = = = 'function') {/ / get the first then approach the return value of the attribute, then if it's a function, Default to promise const then = res.then; If (typeof then === 'function') {// Pass this, new onResolve, new onReject then. Call (res, NewRes => {// Only one if (called) return can be called on success and failure; called = true; // Recursively call handleNewPromise until res is not object or function this.handleNewPromise(newRes, newPromise, resolve, reject); }, newReason => {// Success and failure can only call one if (called) return; called = true; reject(newReason); }) } else { resolve(res); }} else {// Execute the second Promise's resolve method directly if it is a value type and return resolve(res); } // Define the then method to accept two functions as arguments then(onResolve, Const newPromise = new MyPromise((resolve, reject) => {// If state is pending, Add onResolve and onReject to the array. If (this.status === PENDING) {// Since onResolve and onReject accept arguments, we push an anonymous function; this.onResolveArr.push(() => { const result = onResolve(this.result); this.handleNewPromise(result, newPromise, resolve, reject); }) this.onRejectArr.push(() => { const reason = onReject(this.reason); this.handleNewPromise(reason, newPromise, resolve, reject); // Perform onResolve if the state is depressing. This. Status === depressing) {const result = onResolve(this.result); this.handleNewPromise(result, newPromise, resolve, reject); } // If rejected, execute onReject, Reject(this. status === reject) {const reason = onReject(this.reason); this.handleNewPromise(reason, newPromise, resolve, reject); } }) return newPromise; }}Copy the code

Explanation: The then method returns a new promise. The new handleNewPromise method is used to determine whether the result of the first THEN function is a promise. Recursively calls the handleNewPromise method.

So far, I have basically realized my promise, of course, this is not complete, there are some places to do compatible processing, you can discuss ideas in the comments section