If you’re not comfortable with promises, I don’t recommend that you make them a Promise. Read on to answer 45 Promise interview questions.

Step by step to implement Promise source address: click enter,

Introduction of the whole process

  1. Define the overall structure first
  2. Implement the Promise constructor
  3. Realize the promise. Then
  4. Realize the promise. The catch
  5. Realize the promise. Resovle
  6. Realize the promise. Reject
  7. Realize the promise. All
  8. Realize the promise. Race

1. Define the overall structure

  1. Write out the constructor to expose the Promise
/* Custom Promise function module: IIFE */

(function (window) {
    /* Promise constructor executor: executor function */
    function Promise(executor) {

    }

    // Expose Promise
    window.Promise = Promise}) ()
Copy the code
  1. Add methods on the Promise prototype object
 /* The then of the Promise prototype object specifies a success/failure callback that returns a new Promise object */
    Promise.prototype.then = function(onResolved,onRejected){

    }

    /* The. Catch of the Promise prototype object specifies that a failed callback returns a new Promise object */
    Promise.prototype.catch = function(onRejected){

    }
Copy the code
  1. Add methods on the Promise function object
/* The resovle method of the Promise function object returns a Promise object with the specified result */
    Promise.resolve = function(value){

    }

    The reject method of the Promise object returns a Promise that specifies the failed state of Reason */
    Promise.reject = function(value){

    }

    /* The all method of the Promise function object returns a Promise object. The returned Promise state is successful only if all promises are successful */
    Promise.all = function(value){
 }  /* The race method of the Promise function object returns a Promise object whose state is determined by the first completed Promise */ Promise.race = function(value){  } Copy the code

2. Implement the Promise constructor

  1. As you know, constructors have resolve and reject, and both methods are passed to the executor and executed immediately in sync
    /* Promise constructor executor: executor function */
    function Promise(executor) {

        function resovle() {

        }
        function reject() {

        }

        // Execute executor immediately
        executor(resovle,reject)
    }
 Copy the code
  1. As you know, every promise has a state that can be Pending or Resolved, rejected. So we need to add a status, and also, when we use promises like this,
// 例1
var promise = new Promise((resovle,reject) = >{
Copy the code

}) promise.then(resolve= >{},reject=>{})

The state of the promise is still pending. The value and the callback function in the THEN must be stored, so data and callbacks are required

function Promise(executor) {

        var self = self

        self.status = 'pending' // Assign the status attribute to the Promise object, starting with pending
        self.data = undefined // Give the Promise object a data to store the results
        self.callbacks = []  {onResolved(){}, onRejected(){}}

        function resovle() {

        }
        function reject() {
 }  // Execute executor immediately executor(resovle,reject) } Copy the code
  1. It is well known that, based on example 1 above, when we execute resovle (value),
// 例2
var promise = new Promise((resolve,reject) = >{
    setTimeout(function () {
        resolve(1)})})
promise.then(resolve= >{},reject=>{})

Copy the code

Changes the status of the Promise object to resovle, stores the value to data, and executes the previously saved callbacks. Saves the then callbacks in the Promise callbacks).

function resolve(value) {
            // If the current state is not pending, no execution is performed
            if(self.status ! = ='pending') {return
            }
            // Change the status to Resolved
            self.status = 'resolved'
            // Save the value of value
            self.data = value

            // If the callback function is waiting to be executed, execute onResolved asynchronously immediately
            if (self.callbacks.length>0){
                setTimeout((a)= >{
                    self.callbacks.forEach(callbackObj= >{
                        callbackObj.onResolved(value)
                    })
                })
            }
        }
Copy the code
  1. We also know that the state of a promise can only change once, so a resolve execution must determine whether the promise is a pending state or not
function resolve(value) {
            // If the current state is not pending, no execution is performed
            if(this.status ! = ='pending') {return 
            }
            // Change the status to Resolved
            this.status = 'resolved'
            // Save the value of value
            this.data = value

            // If the callback function is waiting to be executed, execute onResolved asynchronously immediately
            if (this.callbacks.length>0){
                setTimeout((a)= >{
                    this.callbacks.forEach(callbackObj= >{
                        callbackObj.onResolved(value)
                    })
                })
            }
        }
Copy the code
  1. The beauty of the reject method is that it works the same way, so there’s no need to describe it here
function reject(value) {
            // If the current state is not pending, no execution is performed
            if(self.status ! = ='pending') {return
            }
            // Change the status to Resolved
            self.status = 'rejected'
            // Save the value of value
            self.data = value

            // If the callback function is waiting to be executed, execute onResolved asynchronously immediately
            if (self.callbacks.length>0){
                setTimeout((a)= >{
                    self.callbacks.forEach(callbackObj= >{
                        callbackObj.onRejected(value)
                    })
                })
            }
        }
Copy the code
  1. We also know that when executor is executed, the Promise state executes reject directly if an exception is executed.
/ / 3
var promise = new Promise((resolve,reject) = >{
I've made an error here
    setTimeout(function () {
        resolve(1)})})Copy the code

To do this, we can use a try catch outside the executor

        try{
            // Execute executor immediately
            executor(resolve,reject)
        }catch (e) { // If the actuator throws an exception, the Promise object changes to the Rejected state
            reject(e)
        }
Copy the code

Ok, now let’s test that out. To test that out, we need to simply implement the THEN and have it push the callbacks in the THEN

   Promise.prototype.then = function(onResolved,onRejected){
        // If the current state is still pending, save the callback function
        this.callbacks.push({
            onResolved,
            onRejected
        })
    }
Copy the code

All right, let’s test it out. It worked.

 // 例4
 let promise = new Promise((resolve,reject) = >{
setTimeout(<span class="hljs-function" style="line-height: 26px;" ><span class="hljs-keyword" style="color: #aa0d91; line-height: 26px;" >function</span> (<span class="hljs-params" style="color: #5c2699; line-height: 26px;" ></span>) </span>{ <span class="hljs-comment" style="color: #007400; line-height: 26px;" >// resolve(1)</span> reject(<span class="hljs-number" style="color: #1c00cf; line-height: 26px;" >1</span>) },<span class="hljs-number" style="color: #1c00cf; line-height: 26px;" >100</span>) })Copy the code


promise.then(
value= >{
console.log("onResolved:",value);
},
reason=>{
console.log("onRejected:",reason); })
Copy the code

3. Implement then methods

As you can see, when you implement THEN, it could be a pending state and you’re going to save the callback function in that then, or it could be resolved or Rejected and you’re going to implement onResolved or onRejected.

Promise.prototype.then = function(onResolved,onRejected){

        var self = this

        if(self.status === 'pending') {// Promise is still in a pending state, save the callback function
            self.callbacks.push({
                onResolved(){onResolved(self.data)},
                onRejected(){onRejected(self.data)}
            })
        }else if(self.status === 'resolved'){
            setTimeout((a)= >{
                onResolved(self.data)
            })
        }else{
            setTimeout((a)= >{
                onResolved(self.data)
            })
        }

    }

Copy the code

Moreover, we know that a new promise is returned after executing then, and the state of the new promise is determined by the execution result of the current THEN.

 Promise.prototype.then = function(onResolved,onRejected){

        var self = this

        return new Promise((resolve,reject) = >{
            if(self.status === 'pending') {// Promise is still in a pending state, save the callback function
                self.callbacks.push({
                    onResolved(){onResolved(self.data)},
                    onRejected(){onRejected(self.data)}
                })
            }else if(self.status === 'resolved'){
                setTimeout((a)= >{
                    onResolved(self.data)
                })
            }else{
                setTimeout((a)= >{
                    onResolved(self.data)
                })
            }
        })

    }
Copy the code

When the current Promise state is Resolved, the OnResolved function can be executed in one of three cases

  1. If the callback does not return a Promise and the promise status of the return is Resolved, value is the returned value.
/ / case 5
    let promise = new Promise((resolve,reject) = >{
        resolve(1)})
    promise.then(
        value= >{
            return value
        },
        reason=>{
            console.log("onRejected:",reason); })Copy the code

So, we can do this

Promise.prototype.then = function(onResolved,onRejected){

        var self = this

        return new Promise((resolve,reject) = >{
            if(self.status === 'pending') {// Promise is still in a pending state, save the callback function
                self.callbacks.push({
                    onResolved(){onResolved(self.data)},
                    onRejected(){onRejected(self.data)}
                })
            }else if(self.status === 'resolved'){
                setTimeout((a)= >{
                    const result = onResolved(self.data)
                    if (result instanceof Promise) {
                    } else {
                    // 1. If the return is resolved and the promise state is resolved, value is the returned value.
                        resolve(result)
                    }
                })
            }else{
                setTimeout((a)= >{
                    onResolved(self.data)
                })
            }
        })

    }
Copy the code
  1. If the callback returns a promise, the result of the return promise is the result of the promise, and as the code shows, we return a new promise. This new promise implements resolve, so the state returned is Resolved
/ / case 6
 let promise = new Promise((resolve,reject) = >{
        resolve(1)})
    promise.then(
        value= >{
            return new Promise((resolve,reject) = >{
                resolve(2)
            })
        },
        reason=>{
            console.log("onRejected:",reason); })Copy the code

So we can do this

Promise.prototype.then = function(onResolved,onRejected){

        var self = this

        return new Promise((resolve,reject) = >{
            if(self.status === 'pending') {// Promise is still in a pending state, save the callback function
                self.callbacks.push({
                    onResolved(){onResolved(self.data)},
                    onRejected(){onRejected(self.data)}
                })
            }else if(self.status === 'resolved'){
                setTimeout((a)= >{
                    const result = onResolved(self.data)
                    if (result instanceof Promise) {// 2. If the callback returns a promise, the return promise is the result of that promise
                        result.then(
                            value= > {resolve(value)},
                            reason => {reject(reason)}
                        )
                    } else {
                        // 1. If the return is resolved and the promise state is resolved, value is the returned value.
                        resolve(result)
                    }
                })
            }else{
                setTimeout((a)= >{
                    onResolved(self.data)
                })
            }
        })

    }

Copy the code

Here’s an explanation:

result.then(
    value => {resolve(value)},
    reason => {reject(reason)}
)
Copy the code

Since we executed resolve in then in Example 6, this callback will result in value => {resolve(value)}, so it will set the data for the new promise that will be returned to value and the state to Resolved.

  1. If onResolved fails and the promise is rejected, try catch can be used
setTimeout((a)= >{
    try{
        const result = onResolved(self.data)
        if (result instanceof Promise) {// 2. If the callback returns a promise, the return promise is the result of that promise
            result.then(
                value= > {resolve(value)},
                reason => {reject(reason)}
            )
        } else {
            // 1. If the return is resolved and the promise state is resolved, value is the returned value.
            resolve(result)
        }
    }catch (e) {
      // 3. If onResolved fails, the promise state is Rejected
        reject(e)
    }
})
Copy the code

Status === ‘rejected

 setTimeout((a)= >{
      try{
          const result = onRejected(self.data)
          if (result instanceof Promise) {// 2. If the callback returns a promise, the return promise is the result of that promise
              result.then(
                  value= > {resolve(value)},
                  reason => {reject(reason)}
              )
          } else {
              // 1. If the return is resolved and the promise state is resolved, value is the returned value.
              resolve(result)
          }
      }catch (e) {
          // 3. If onResolved fails, the promise state is Rejected
          reject(e)
      }
  })
Copy the code

Resolve: onResolved(self.data) and onRejected(self.data

 self.callbacks.push({
    onResolved(){onResolved(self.data)},
    onRejected(){onRejected(self.data)}
})
Copy the code

to

if(self.status === 'pending') {// Promise is still in a pending state, save the callback function
self.callbacks.push({
    onResolved(){
        try{
            const result = onResolved(self.data)
            if (result instanceof Promise) {// 2. If the callback returns a promise, the return promise is the result of that promise
                result.then(
                    value= > {resolve(value)},
                    reason => {reject(reason)}
                )
            } else {
                // 1. If the return is resolved and the promise state is resolved, value is the returned value.
                resolve(result)
            }
        }catch (e) {
            // 3. If onResolved fails, the promise state is Rejected
            reject(e)
        }
    },
Copy the code

At this point, we see that there is so much code that it makes sense to wrap it

function handle(callback) { try{ const result = callback(self.data) if (result instanceof Promise){ // 2. If the callback returns a promise, Result. then(value => {resolve(value)}, reason => {reject(reason)})} else {// 1. If the callback does not return a Promise and the promise status of the return is Resolved, value is the returned value. resolve(result) } }catch (e) { // 3. When onResolved fails, the promise is rejected Reject (e)}}Copy the code

It’s refreshing

   Promise.prototype.then = function(onResolved,onRejected){

        var self = this

        return new Promise((resolve,reject) = >{
           /* Calls the specified callback function based on the result of execution. Change the return promise state */
            function handle(callback) {
                try{
                    const result = callback(self.data)
                    if (result instanceof Promise) {// 2. If the callback returns a promise, the return promise is the result of that promise
                        result.then(
                            value= > {resolve(value)},
                            reason => {reject(reason)}
                        )
                    } else {
                        // 1. If the return is resolved and the promise state is resolved, value is the returned value.
                        resolve(result)
                    }
                }catch (e) {
                    // 3. If onResolved fails, the promise state is Rejected
                    reject(e)
                }
            }
            if(self.status === 'pending') {// Promise is still in a pending state, save the callback function
                self.callbacks.push({
                    onResolved(){
                        handle(onResolved)
                    },
                    onRejected(){
                        handle(onRejected)
                    }
                })
            }else if(self.status === 'resolved'){
                setTimeout((a)= >{
                    handle(onResolved)
                })
            }else{ // When status === 'rejected'
                setTimeout((a)= >{
                    handle(onRejected)
                })
            }
        })

    }

Copy the code

In addition, we also know that promises can happen through, for example

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)
Copy the code

Running result: 1

Explanation:.then or.catch parameters are expected to be functions, and passing non-functions will result in value penetration. Value pass-through can be understood as saying that a THEN is invalid if it is passed to something other than a function.

Therefore, to implement the direct pass feature, we can implement it like this

Add these two sentences to determine whether value pass through should occur

onResolved = typeof onResolved === 'function'? onResolved: value= > value
onRejected = typeof onRejected === 'function'? onRejected: reason= > {throw reason}
Copy the code
 Promise.prototype.then = function(onResolved,onRejected){
        onResolved = typeof onResolved === 'function'? onResolved: value= > value
        onRejected = typeof onRejected === 'function'? onRejected: reason= > {throw reason}
        var self = this

        return new Promise((resolve,reject) = >{

            /* Calls the specified callback function based on the result of execution. Change the return promise state */
            function handle(callback) {
                try{
                    const result = callback(self.data)
                    if (result instanceof Promise) {// 2. If the callback returns a promise, the return promise is the result of that promise
                        result.then(
                            value= > {resolve(value)},
                            reason => {reject(reason)}
                        )
                    } else {
                        // 1. If the return is resolved and the promise state is resolved, value is the returned value.
                        resolve(result)
                    }
                }catch (e) {
                    // 3. If onResolved fails, the promise state is Rejected
                    reject(e)
                }
            }
            if(self.status === 'pending') {// Promise is still in a pending state, save the callback function
                self.callbacks.push({
                    onResolved(){
                        handle(onResolved)
                    },
                    onRejected(){
                        handle(onRejected)
                    }
                })
            }else if(self.status === 'resolved'){
                setTimeout((a)= >{
                    handle(onResolved)
                })
            }else{ // When status === 'rejected'
                setTimeout((a)= >{
                    handle(onRejected)
                })
            }
        })

    }

Copy the code

3. Implement the catch method

It is well known that the catch method acts like the second song callback in then, so we can do this

Promise.prototype.catch = function(onRejected){
    return this.then(undefined,onRejected)
}
Copy the code

Oh, my God, it’s so easy

4. Realize the Promise. Resolve

As we all know, the promise.resolve method can pass three values

  1. Not a promise
  2. The promise of a successful state
  3. Failed state promises

    Promise.resolve(1)
    Promise.resolve(Promise.resolve(1))
    Promise.resolve(Promise.reject(1))
Copy the code

It’s actually a little bit like implementing the then above

Promise.resolve = function(value){
  return new Promise((resolve,reject) = >{
      if (value instanceof Promise) {// If value is promise
          value.then(
              value= > {resolve(value)},
              reason => {reject(reason)}
          )
      } else{
          // If value is not a promise
          resolve(value)
      }

  }

}
Copy the code

5. Realize the Promise. Reject

It’s easy to implement this, just return a Promise with the state Rejected

The reject method of the Promise object returns a Promise that specifies the failed state of Reason */
Promise.reject = function(reason){
    return new Promise((resolve,reject) = >{
        reject(reason)
    })
}

Copy the code

6. Realize the Promise. All

We know that this method returns a promise

    /* The all method of the Promise function object returns a Promise object. The returned Promise state is successful only if all promises are successful */
    Promise.all = function(promises){
        return new Promise((resolve,reject) = >{
})}Copy the code

Copy the code

The state of this promise is determined by the result of iterating through each promise

    /* The all method of the Promise function object returns a Promise object. The returned Promise state is successful only if all promises are successful */
    Promise.all = function(promises){
        return new Promise((resolve,reject) = >{
            // Go through Promises, get the result of each promise
            promises.forEach((p,index) = >{
})})}Copy the code

Copy the code

There are two outcomes:

  1. If there is a Reject state, the reject state is returned
 Promise.all = function(promises){
        return new Promise((resolve,reject) = >{
            // Go through Promises, get the result of each promise
            promises.forEach((p,index) = >{
                p.then(
                    value= > {
}, reason =&gt; { <span class="hljs-comment" style="color: #007400; line-height: 26px;" Reject </span> reject(reason)})})}Copy the code

Copy the code

  1. When all promises are in resolved state, the returned promise state is Resolved and the value generated by each promise is passed along
   Promise.all = function(promises){
      const values = new Array(promises.length)
      var resolvedCount = 0 // Count the number of resolved promises
      return new Promise((resolve,reject) = >{
          // Go through Promises, get the result of each promise
          promises.forEach((p,index) = >{
              p.then(
                  value= > {
                      // p in resolved state, save the value
                      values[index] = value
                      resolvedCount++;
                      // If all p are resolved, the return promise state is Resolved
                      if(resolvedCount === promises.length){
                          resolve(values)
                      }
                  },
                  reason => { // The return promise state is reject when there is a single failure
                      reject(reason)
                  }
              )
          })
      })
  }
Copy the code

That seems to work, but there’s actually a problem here, which is that all doesn’t always pass in an array that’s a promise object, it might

All (a/p, 2, 3, p)Copy the code

So you need to wrap a number that isn’t a promise as a promise

    Promise.all = function(promises){
        const values = new Array(promises.length)
        var resolvedCount = 0 // Count the number of resolved promises
        return new Promise((resolve,reject) = >{
            // Go through Promises, get the result of each promise
            promises.forEach((p,index) = >{
                Promise.resolve(p).then(
                    value= > {
                        // p in resolved state, save the value
                        values[index] = value
                        resolvedCount++;
                        // If all p are resolved, the return promise state is Resolved
                        if(resolvedCount === promises.length){
                            resolve(values)
                        }
                    },
                    reason => { // The return promise state is reject when there is a single failure
                        reject(reason)
                    }
                )
            })
        })
    }
Copy the code

7. Realize the Promise. Race

This method is much simpler to implement than All

  /* The race method of the Promise function object returns a Promise object whose state is determined by the first completed Promise */
    Promise.race = function(promises){
        return new Promise((resolve,reject) = >{
            // Go through Promises, get the result of each promise
            promises.forEach((p,index) = >{
                Promise.resolve(p).then(
                    value= > {
                        // As long as there is a success, return the state of Nine-tailed Resolved promise
                        resolve(value)

                    },
                    reason => { // The return promise state is reject when there is a single failure
                        reject(reason)
                    }
                )
            })
        })
    }

Copy the code

This article is formatted using MDNICE