Promise:

So let’s first create aMyPromise

 class MyPromise {
   constructor(executor) {
     this.state = 'pending' / / state
     this.value = undefined // Save resolve
     this.error = undefined // Save the reject value

     / / resolve function
     const resolve = value= > {
       if (this.state === 'pending') {
         this.state = 'fullFilled'
         this.value = value
       }
     }

      / / reject function
      const reject = error= > {
        if (this.state === 'pending') {
          this.state = 'rejected'
          this.error = error
        }
      }

      // Executes the function passed in via new MyPromise()
      executor(resolve, reject)
    }

    / / then method
    then(onFullFilled, onRejected) {
      // If the state is fullFilled, execute the resolve callback
      if (this.state === 'fullFilled') {
        onFullFilled(this.value)
      }
      // If the state is fullFilled, execute the reject callback
      if (this.state === 'rejected') {
         onRejected(this.error)
      }
    }
  }
  // Test basic functionality
  new MyPromise((resolve, reject) = > {
    if (Math.random() < 0.5) {
      resolve('fullFilled')}else {
      reject('rejected')
    }
  }).then(value= > {
    console.log(value)
  }, error= > {
    console.log(error)
  })
Copy the code

This code implements the simplest resolve and reject, but in a Promise, syntactic errors will be caught and reject will be triggered, so error trapping is required

Implement error capture

 try {
   // Executes the function passed in via new MyPromise()
   executor(resolve, reject)
 } catch (e) {
   reject(e)
 }

// Test the capture function
new MyPromise((resolve, reject) = > {
  // Intentionally print an undefined value
  console.log(a)
}).then(value= > {
  console.log(value)
}, error= > {
  // Will trigger the failed callback function
  console.log(error)
})
Copy the code

This catches errors and fires reject, but if a Promise fires resolve/ Reject asynchronously, success and failure callbacks in THEN won’t be triggered properly, so you need to save success and failure callbacks in advance using a publish-subscribe mechanism. The callback is then triggered when resolve/ Reject fires

Implement asynchronous triggeringresolve/reject

.this.onResolvedCallback = [] // Save the resolve callback
this.onRejectedCallback = [] // Save the reject callback
 
/ / resolve function
const resolve = value= > {
  if (this.state === 'pending') {
    this.state = 'fullFilled'
    this.value = value
    this.onResolvedCallback.forEach(fn= > fn())
  }
}

/ / reject function
const reject = error= > {
  if (this.state === 'pending') {
     this.state = 'rejected'
     this.error = error
     this.onRejectedCallback.forEach(fn= > fn())
  }
}
 / / then method
 then(onFullFilled, onRejected){...// If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
   if (this.state === 'pending') {
     this.onResolvedCallback.push(() = > {
       onFullFilled(this.value)
     })
     
     this.onRejectedCallback.push(() = > {
       onRejected(this.error)
     })
   }
 }

// Test asynchronous code
new MyPromise((resolve, reject) = > {
  setTimeout(() = > {
    if (Math.random() < 0.5) {
      resolve(10)}else {
      reject(-10)}},1000)
}).then(value= > {
  console.log(value)
}, error= > {
  console.log(error)
})
Copy the code

The successful and failed callbacks in THEN can also be fired asynchronously if resolve/ Reject is fired, and the next step is to implement the chained calls to then

implementationthenThe chain call to

/ / then method
then(onFullFilled, onRejected) {
  let x

  return new MyPromise((resolve, reject) = > {
    // If the state is fullFilled, execute the resolve callback
    if (this.state === 'fullFilled') {
      x = onFullFilled(this.value)
      resolve(x)
    }
    // If the state is fullFilled, execute the reject callback
    if (this.state === 'rejected') {
      x = onRejected(this.error)
      resolve(x)
    }
    // If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
    if (this.state === 'pending') {
      this.onResolvedCallback.push(() = > {
        x = onFullFilled(this.value)
        resolve(x)
      })
      this.onRejectedCallback.push(() = > {
        x = onRejected(this.error)
        resolve(x)
      })
    }
  })
}

  // Test chained calls
  const myPromise = new MyPromise((resolve, reject) = > {
    if (Math.random() < 0.5) {
      resolve(10)}else {
      reject(-10)
    }
  })
  myPromise.then(value= > {
    console.log('sucess:', value)
    return value + 2
  }, error= > {
    console.log('fail:', error)
    return error - 2
  }).then(value= > {
    console.log('sucess:', value)
    return value + 8
  }, error= > {
    console.log('fail:', error)
    return error - 8
  }).then(value= > {
    console.log('sucess:', value)
    return value + 10
  }, error= > {
    console.log('fail:', error)
    return error - 10
  })
Copy the code

This implements the chain of calls to THEN, and ensures that each successful and failed callback to then returns a promise object, followed by an error-catching mechanism

thenChain operation adds error capture

/ / then method
then(onFullFilled, onRejected) {
  let x

  return new MyPromise((resolve, reject) = > {
    // If the state is fullFilled, execute the resolve callback
    if (this.state === 'fullFilled') {
      // Add an error-catching mechanism
      try {
        x = onFullFilled(this.value)
        resolve(x)
      } catch (e) {
        reject(e)
      }
    }
    // If the state is fullFilled, execute the reject callback
    if (this.state === 'rejected') {
      // Add an error-catching mechanism
      try {
        x = onRejected(this.error)
        resolve(x)
      } catch (e) {
        reject(e)
      }
    }
    // If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
    if (this.state === 'pending') {
      this.onResolvedCallback.push(() = > {
        // Add an error-catching mechanism
        try {
          x = onFullFilled(this.value)
          resolve(x)
        } catch (e) {
          reject(e)
        }
      })
      this.onRejectedCallback.push(() = > {
        // Add an error-catching mechanism
        try {
          x = onRejected(this.error)
          resolve(x)
        } catch (e) {
          reject(e)
        }
      })
    }
  })
}

  // Test the error trapping function in chained calls
  const myPromise = new MyPromise((resolve, reject) = > {
    if (Math.random() < 0.5) {
      resolve(10)}else {
      reject(-10)
    }
  })
  myPromise.then(value= > {
    // Intentionally print an undefined value
    console.log(a)
    return value + 2
  }, error= > {
    // Intentionally print an undefined value
    console.log(a)
    return error - 2
  }).then(value= > {
    console.log('sucess:', value)
  }, error= > {
    // Will trigger the failed callback function
    console.log('fail:', error)
  })
Copy the code

Once this is done, there is a problem. If I actively return a promise in the success or failure callback of then, how do I deal with the relationship between that promise and the promise returned by default?

Compatible return value ispromiseCase of object

/ / then method
then(onFullFilled, onRejected) {
    const promise =  new MyPromise((resolve, reject) = > {
        let x

        // If the state is fullFilled, execute the resolve callback
        if (this.state === 'fullFilled') {
            try {
                x = onFullFilled(this.value)
                resolvePromise(x, resolve, reject)
            } catch (err) {
                reject(err)
            }
        }

        // If the status is Rejected, the reject callback is executed
        if (this.state === 'rejected') {
            try {
                x = onRejected(this.error)
                resolvePromise(x, resolve, reject)
            } catch (err) {
                reject(err)
            }
        }

        // If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
        if (this.state === 'pending') {
            this.onResolvedCallback.push(() = > {
                try {
                    x = onFullFilled(this.value)
                    resolvePromise(x, resolve, reject)
                } catch (err) {
                    reject(err)
                }
            })
            this.onRejectedCallback.push(() = > {
                try {
                    x = onRejected(this.error)
                    resolvePromise(x, resolve, reject)
                } catch (err) {
                    reject(err)
                }
            })
        }
    })

    function resolvePromise(x, resolve, reject) {
        If the return value is a Promise object
        if (typeof x === 'object'&& x ! = =null && typeof x.then === 'function') {
            x.then(value= > {
                resolve(value)
            }, err= > {
                reject(err)
            })
        } else {
            resolve(x)
        }
    }

    return promise
}

// Test the case where the return value is a Promise object
const myPromise = new MyPromise((resolve, reject) = > {
  setTimeout(() = > {
    if (Math.random() < 0.5) {
      resolve(10)}else {
      reject(-10)
    }
  })
})
myPromise.then(value= > {
  console.log('sucess0:', value)
  // Actively return a Promise object
  return new MyPromise((resolve, reject) = > {
    resolve(Awesome!)})},error= > {
  console.log('fail0:', error)
  return new MyPromise((resolve, reject) = > {
    resolve(222)
  })
})
.then(value= > {
  console.log('sucess1:', value)
  return value
}, error= > {
  console.log('fail1:', error)
  return error
})
.then(value= > {
  console.log('sucess2:', value)
  return value
}, error= > {
  console.log('fail2:', error)
  return error
})
Copy the code

Add a resolvePromise method to determine the type of the returned object. If it is a Promise object, resolve the resolved value again. However, if a promise object is returned with nested promises, recursive processing is required

Recursive processing of the return value of the Promise object

function resolvePromise(x, resolve, reject) {
    If the return value is a Promise object
    if (typeof x === 'object'&& x ! = =null && typeof x.then === 'function') {
        console.log('aaa')
        x.then(value= > {
            // Recursively process the promise return value
            resolvePromise(value, resolve, reject)
        }, err= > {
            reject(err)
        })
    } else {
        console.log('bbb')
        resolve(x)
    }
}
// Test the case where the return value is a Promise object
const myPromise = new MyPromise((resolve, reject) = > {
  setTimeout(() = > {
    if (Math.random() < 0.5) {
      resolve(10)}else {
      reject(-10)
    }
  })
})
myPromise.then(value= > {
  console.log('sucess0:', value)
  return new MyPromise((resolve, reject) = > {
    // Nested multiple promises
    resolve(new MyPromise((resolve, reject) = > {
      resolve(Awesome!)})}})),error= > {
  console.log('fail0:', error)
  return new MyPromise((resolve, reject) = > {
    resolve(222)
  })
})
.then(value= > {
  console.log('sucess1:', value)
  return value
}, error= > {
  console.log('fail1:', error)
  return error
})
.then(value= > {
  console.log('sucess2:', value)
  return value
}, error= > {
  console.log('fail2:', error)
  return error
})
Copy the code

Complete code

class MyPromise {
    constructor(executor) {
      this.state = 'pending' / / state
      this.value = undefined // Save resolve
      this.error = undefined // Save the reject value
      this.onResolvedCallback = [] // Save the resolve callback
      this.onRejectedCallback = [] // Save the reject callback

      / / resolve function
      const resolve = value= > {
        if (this.state === 'pending') {
          this.state = 'fullFilled'
          this.value = value
          this.onResolvedCallback.forEach(fn= > fn())
        }
      }

      / / reject function
      const reject = error= > {
        if (this.state === 'pending') {
          this.state = 'rejected'
          this.error = error
          this.onRejectedCallback.forEach(fn= > fn())
        }
      }

      try {
        // Executes the function passed in via new MyPromise()
        executor(resolve, reject)
      } catch (e) {
        reject(e)
      }
    }

    / / then method
    then(onFullFilled, onRejected) {
      const promise =  new MyPromise((resolve, reject) = > {
        let x

        // If the state is fullFilled, execute the resolve callback
        if (this.state === 'fullFilled') {
          try {
            x = onFullFilled(this.value)
            resolvePromise(x, resolve, reject)
          } catch (err) {
            reject(err)
          }
        }

        // If the status is Rejected, the reject callback is executed
        if (this.state === 'rejected') {
          try {
            x = onRejected(this.error)
            resolvePromise(x, resolve, reject)
          } catch (err) {
            reject(err)
          }
        }

        // If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
        if (this.state === 'pending') {
          this.onResolvedCallback.push(() = > {
            try {
              x = onFullFilled(this.value)
              resolvePromise(x, resolve, reject)
            } catch (err) {
              reject(err)
            }
          })
          this.onRejectedCallback.push(() = > {
            try {
              x = onRejected(this.error)
              resolvePromise(x, resolve, reject)
            } catch (err) {
              reject(err)
            }
          })
        }
      })

      function resolvePromise(x, resolve, reject) {
        If the return value is a Promise object
        if (typeof x === 'object'&& x ! = =null && typeof x.then === 'function') {
          x.then(value= > {
            resolvePromise(value, resolve, reject)
          }, err= > {
            reject(err)
          })
        } else {
          resolve(x)
        }
      }

      return promise
    }
  }
Copy the code