手写promise 中then catch finally以及静态方法resolve,reject,all,allSettled,race

  • 初始化 promise
js 复制代码
// 定义三种状态
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECT = 'reject'

class MyPromise {
  constructor(executor){
    this.status = PROMISE_STATUS_PENDING  // 初始化为pending状态
    this.value = undefined // 存储成功时候的值
    this.reason = undefined  // 存储失败时候的值
    const resolve = (value)=>{
      // 当状态为pending时 更改为成功状态
      if(this.status === PROMISE_STATUS_PENDING){
        this.status = PROMISE_STATUS_FULFILLED
        this.value = value // 保存成功返回的值
         console.log('resolve:',value)
      }
     
    }
    const reject = (reason)=>{
      // 当状态为pending时 更改为失败状态
      if(this.status === PROMISE_STATUS_PENDING){
        this.status = PROMISE_STATUS_REJECT
        this.reason = reason // 保存失败返回的值
        console.log('reject:',reason)
      }
    }
    executor(resolve,reject)
  }
}

// new 自己定义的promiase 
const promise = new MyPromise((resolve,reject)=>{
  // console.log('函数被直接调用')
  resolve(111)
})
  • 增加then方法调用
js 复制代码
// ... 省略上面已经定义过的东西,只写关键代码 (...表示省略的重复定义)
class MyPromise {
  constructor(executor){
    // ...
    const resolve = (value)=>{
      // 当状态为pending时 更改为成功状态
      if(this.status === PROMISE_STATUS_PENDING){
        // 建立一个微任务,保证promise.then先执行,才能调用到this.onFulfilled函数,否则报this.onFulfilled不是一个函数
        // 也可以使用setTimeout(宏任务),queueMicrotask 是 微任务,当前回合下就能执行
        queueMicrotask(()=>{
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value // 保存成功返回的值
          console.log('resolve:',value)
          this.onFulfilled(this.value)
        })
      }
     
    }
    const reject = (reason)=>{
      // 当状态为pending时 更改为失败状态
      if(this.status === PROMISE_STATUS_PENDING){
        // 建立一个微任务,保证promise.then先执行,才能调用到this.onRejected函数,否则报this.onRejected不是一个函数
        // 也可以使用setTimeout(宏任务),queueMicrotask 是 微任务,当前回合下就能执行
        queueMicrotask(()=>{
          this.status = PROMISE_STATUS_REJECT
          this.reason = reason // 保存失败返回的值
          console.log('reject:',reason)
          this.onRejected(this.reason)
        })
      }
    }
    executor(resolve,reject)
  }

  then(onFulfilled,onRejected){
    this.onFulfilled = onFulfilled
    this.onRejected = onRejected
  }
}

const promise = new MyPromise((resolve,reject)=>{
  resolve(111)
  // reject(444)
})

promise.then(res=>{
  console.log('res:',res)
},err=>{
    
})
  • 上述代码,存在问题,如:用户重复使用promise,则只会执行最后一次promise中传递的函数,后面不会执行

问题事例:

js 复制代码
const promise = new MyPromise((resolve,reject)=>{
  resolve(111)
  // reject(444)
})

// 第一次调用
promise.then(res=>{
  console.log('res:',res)
},err=>{
    
})

// 第二次调用
promise.then(res=>{
  console.log('res2:',res)
},err=>{
    
})

解决办法:增加两个callback数组,分别存放成功,失败的函数,后面循环调用执行,关键代码如下:

js 复制代码
class MyPromise {
  constructor(executor){
    // ...
    this.onFulfilledCallBack = []
    this.onRejectCallBack = []
    const resolve = (value)=>{
      // 当状态为pending时 更改为成功状态
      if(this.status === PROMISE_STATUS_PENDING){
        queueMicrotask(()=>{
        // queueMicrotask 会重启一个微任务执行,需要判断status状态不是pending时,则不往下执行
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value // 保存成功返回的值
          // 循环调用成功时的回掉
          this.onFulfilledCallBack.forEach(fn=>{
            fn(this.value)
          })
        })
      }
     
    }
    const reject = (reason)=>{
      // 当状态为pending时 更改为失败状态
      if(this.status === PROMISE_STATUS_PENDING){
        queueMicrotask(()=>{
        // queueMicrotask 会重启一个微任务执行,需要判断status状态不是pending时,则不往下执行
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECT
          this.reason = reason // 保存失败返回的值
          // 循环调用失败时的回掉
          this.onRejectCallBack.forEach(fn=>{
            fn(this.reason)
          })
        })
      }
    }
    executor(resolve,reject)
  }

  then(onFulfilled,onRejected){
    // 将成功和失败回掉保存到callBack函数中
    this.onFulfilledCallBack.push(onFulfilled)
    this.onRejectCallBack.push(onRejected)
  }
}

const promise = new MyPromise((resolve,reject)=>{
  resolve(111)
  // reject(444)
})

promise.then(res=>{
  console.log('res:',res)
})

promise.then(res2=>{
  console.log('res2:',res2)
})
  • 当有setTimeout函数延迟执行时,上述代码不会执行setTimeout里的promise语句,如下:
js 复制代码
promise.then(res=>{
  console.log('res:',res)
})
// promise确定了状态 即不会执行setTimeout
setTimeout(()=>{
    promise.then(res=>{
      console.log('res:',res)
    })
},1000)

原因:再执行非setTimeout中promise后,status会变成fulfilled状态,status成了一种已确认的状态。所以修改then如下:

js 复制代码
  then(onFulfilled,onRejected){
    console.log('this.status:',this.status)
    // 状态若是成功,则直接执行
    if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled){
      onFulfilled(this.value)
    }
    // 状态若是失败,则直接执行
    if(this.status === PROMISE_STATUS_REJECT && onRejected){
      onRejected(this.reason)
    }
    // 将成功和失败回掉保存到callBack函数中
    if(this.status === PROMISE_STATUS_PENDING){
      this.onFulfilledCallBack.push(onFulfilled)
      this.onRejectCallBack.push(onRejected)
    }
    
  }
  • 解决then链式调用问题:如下实例
js 复制代码
promise.then(res=>{
  console.log('res:',res)
}).then(res1=>{
  // 此then 调用会报错
  console.log('res1:',res)
})

原因:上面代码在调用一次then后,没有返回promise格式,导致在then链式调用会进行报错,then函数改动如下:

js 复制代码
then(onFulfilled,onRejected){
    console.log('this.status:',this.status)
    return new MyPromise((resolve,reject)=>{
       // 状态若是成功,则直接执行
      if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled){
        // 直接调用onFulfilled函数,resolve返回结果
        const value = onFulfilled(this.value)
        resolve(value)
      }
      // 状态若是失败,则直接执行
      if(this.status === PROMISE_STATUS_REJECT && onRejected){
      // 直接调用onRejected函数,虽说是reject
        const reason = onRejected(this.reason)
        resolve(reason)
      }
      // 将成功和失败回掉保存到callBack函数中
      if(this.status === PROMISE_STATUS_PENDING){
        this.onFulfilledCallBack.push(()=>{
          const value = onFulfilled(this.value)
          resolve(value)
        })
        this.onRejectCallBack.push(()=>{
          const reject = onRejected(this.reason)
          resolve(reject)
        })
      }
    })
  }
  • 异常处理,如在调用中抛出throw new Error()场景,实例代码如下:
js 复制代码
// 实例1
const promise = new MyPromise((resolve,reject)=>{
  // 直接抛出异常
  throw new Error(' 直接 抛出 异常')
})

// 实例2 resolve中抛出异常
promise.then(res=>{
  console.log('res:',res)
  throw new Error('err message')
},err=>{
  console.log('err:',err)
}).then(res1=>{
  console.log('res1:',res1)
},err1=>{
  console.log('err1:',err1)
})

// 实例3 reject中抛出异常
promise.then(res=>{
  console.log('res:',res)
},err=>{
  console.log('err:',err)
  throw new Error('err message')
}).then(res1=>{
  console.log('res1:',res1)
},err1=>{
  console.log('err1:',err1)
})

解决办法:在代码函数调用中增加try catch 处理

js 复制代码
// 工具函数
function execFnWithCatchError(execFn,value,resolve,reject){
  try{
    const result = execFn(value)
    resolve(result)
  }
  catch(err){
    reject(err)
  }
}

// then 方法修改为:
then(onFulfilled,onRejected){
    console.log('this.status:',this.status)
    return new MyPromise((resolve,reject)=>{
       // 状态若是成功,则直接执行
      if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled){
        // 调用封装的try catch 函数
        execFnWithCatchError(onFulfilled,this.value,resolve,reject)
      }
      // 状态若是失败,则直接执行
      if(this.status === PROMISE_STATUS_REJECT && onRejected){
         // 调用封装的try catch 函数
        execFnWithCatchError(onRejected,this.reason,resolve,reject)
      }
      // 将成功和失败回掉保存到callBack函数中
      if(this.status === PROMISE_STATUS_PENDING){
        this.onFulfilledCallBack.push(()=>{
          // 调用封装的try catch 函数
          execFnWithCatchError(onFulfilled,this.value,resolve,reject)
        })
        this.onRejectCallBack.push(()=>{
           // 调用封装的try catch 函数
          execFnWithCatchError(onRejected,this.reason,resolve,reject)
        })
      }
    })
  }
  • 实现catch 方法
js 复制代码
// 实例调用如下:
promise.then(res=>{
  console.log('res:',res)
}).catch(err1=>{
  console.log('catch err:',err1)
})

// 增加catch方法
catch(onRejected){
    // 可以直接调用then方法,把onFulfilled方法设置为undefined
    // 修改then方法,当onFulfilled为undefined时,返回一个throw err 报错,流程走到下一步
    this.then(undefined,onRejected)
}

// then方法也需要配合改造
then(onFulfilled,onRejected){
    // 处理onRejected为undefined的时候
    const defaultOnRejected = ((err)=>{throw err})
    onRejected = onRejected || defaultOnRejected
    return new MyPromise((resolve,reject)=>{
       // 状态若是成功,则直接执行
      if(this.status === PROMISE_STATUS_FULFILLED){
        // 调用封装的try catch 函数
        execFnWithCatchError(onFulfilled,this.value,resolve,reject)
      }
      // 状态若是失败,则直接执行
      if(this.status === PROMISE_STATUS_REJECT){
         // 调用封装的try catch 函数
        execFnWithCatchError(onRejected,this.reason,resolve,reject)
      }
      // 将成功和失败回掉保存到callBack函数中
      if(this.status === PROMISE_STATUS_PENDING){
      // 当 onFulfilled 不为undefined时,才缓存
        if(onFulfilled) this.onFulfilledCallBack.push(()=>{
          // 调用封装的try catch 函数
          execFnWithCatchError(onFulfilled,this.value,resolve,reject)
        })
        // 当 onRejected 不为undefined时,才缓存
        if(onRejected) this.onRejectCallBack.push(()=>{
           // 调用封装的try catch 函数
          execFnWithCatchError(onRejected,this.reason,resolve,reject)
        })
      }
    })
  }
  • 增加 finally 方法
js 复制代码
// finally 调用
promise.then(res=>{
  console.log('res:',res)
}).catch(err1=>{
  console.log('catch err:',err1)
}).finally(()=>{
  console.log('finally')
})

// 添加finally 方法
// 无论是fulfilled还是rejected 都需要执行finally里的函数
finally(onFinally){
    // 直接调用 then 方法
    this.then(()=>{
      onFinally()
    },()=>{
      onFinally()
    })
}

// 在then方法中增加 onFulfilled 为undefined时的处理
then(onFulfilled,onRejected){
    // console.log('this.status:',onFulfilled)
    // 处理onRejected为undefined的时候
    const defaultOnRejected = (err)=>{throw err}
    onRejected = onRejected || defaultOnRejected

    // 处理onFulfilled为undefined的时候
    const defaultOnFulfilled = (value) => { return value }
    onFulfilled = onFulfilled || defaultOnFulfilled

    // ...
 }
 // 还需要修改下catch方法,需要把catch的promise结果进行返回
 catch(onRejected){
    // 可以直接调用then方法,把onFulfilled方法设置为undefined
    // 修改then方法,当onFulfilled为undefined时,返回一个throw err 报错,流程走到下一步
    return this.then(undefined,onRejected)
 }
 
  • 增加 静态 resolve 方法
js 复制代码
// 调用方法
MyPromise.resolve('this is a resolve').then(res=>{
  console.log('res:',res)
})

// 增加 static resolve 方法
static resolve(value){
    // new 当前自定义的类
    return new MyPromise(resolve=>{
      resolve(value)
    })
 }
  • 增加 静态 reject 方法
js 复制代码
// 调用方法
MyPromise.reject('this is a reject').then(res=>{
  console.log('res:',res)
})

// 增加 static reject 方法
static reject(reason){
    // new 当前自定义的类
    return new MyPromise(,reject=>{
      reject(reason)
    })
}
  • 增加 静态 all 方法
js 复制代码
// 调用实例
const promise = new MyPromise((resolve,reject)=>{
  resolve(44355)
  // reject(555)
  // throw new Error(' 直接 抛出 异常')
})
const promise1 = new MyPromise((resolve,reject)=>{
  resolve(443232)
  // reject(444)
  // throw new Error(' 直接 抛出 异常')
})
const promise2 = new MyPromise((resolve,reject)=>{
  // resolve(111)
  reject(444)
  // throw new Error(' 直接 抛出 异常')
})

MyPromise.all([promise,promise1,promise2]).then(res=>{
  console.log('all res:',res)
}).catch(err=>{
  console.log('all err:',err);
})


// 增加 all 方法
static all(promises){
    return new MyPromise((resolve,reject)=>{
      const values = []
      promises.forEach(item=>{
        item.then(res=>{
          values.push(res)
          if(values.length === promises.length){
            resolve(values)
          }
        }).catch(err=>{
          reject(err)
        })
      })
    })
}
    
  • 增加 static allSettled 方法
js 复制代码
// 调用方式
const promise = new MyPromise((resolve,reject)=>{
  resolve(44355)
  // reject(555)
  // throw new Error(' 直接 抛出 异常')
})
const promise1 = new MyPromise((resolve,reject)=>{
  resolve(443232)
  // reject(444)
  // throw new Error(' 直接 抛出 异常')
})
const promise2 = new MyPromise((resolve,reject)=>{
  // resolve(111)
  reject(444)
  // throw new Error(' 直接 抛出 异常')
})

MyPromise.allSettled([promise,promise1,promise2]).then(res=>{
  console.log('all res:',res)
}).catch(err=>{
  console.log('all err:',err);
})

// allSettlted 方法
static allSettled(promises){
    return new MyPromise((resolve,reject)=>{
      const values = []
      promises.forEach(item=>{
        item.then(res=>{
          values.push({status:'fulfilled',value:res})
        }).catch(err=>{
          values.push({status:'rejected',value:err})
        })
      })
      resolve(values)
    })
}
  • 增加 static race 方法
js 复制代码
// 调用方式
const promise = new MyPromise((resolve,reject)=>{
  resolve(44355)
  // reject(555)
  // throw new Error(' 直接 抛出 异常')
})
const promise1 = new MyPromise((resolve,reject)=>{
  resolve(443232)
  // reject(444)
  // throw new Error(' 直接 抛出 异常')
})
const promise2 = new MyPromise((resolve,reject)=>{
  // resolve(111)
  reject(444)
  // throw new Error(' 直接 抛出 异常')
})

MyPromise.race([promise,promise1,promise2]).then(res=>{
  console.log('all res:',res)
}).catch(err=>{
  console.log('all err:',err);
})

// 增加 race 方法
static race(promises){
    return new MyPromise((resolve,reject)=>{
      promises.forEach(item=>{
        item.then(res=>{
          resolve(res)
        }).catch(err=>{
          reject(err)
        })
      })
    })
}
  • 完整代码如下:
js 复制代码
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECT = 'reject'

// 工具函数
function execFnWithCatchError(execFn,value,resolve,reject){
  try{
    const result = execFn(value)
    resolve(result)
  }
  catch(err){
    reject(err)
  }
}

class MyPromise {
  
  constructor(executor){
    this.status = PROMISE_STATUS_PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledCallBack = []
    this.onRejectCallBack = []
    const resolve = (value)=>{
      // 当状态为pending时 更改为成功状态
      if(this.status === PROMISE_STATUS_PENDING){
        // 建立一个微任务,保证promise.then先执行,才能调用到this.onFulfilled函数,否则报this.onFulfilled不是一个函数
        // 也可以使用setTimeout(宏任务),queueMicrotask 是 微任务,当前回合下就能执行
        queueMicrotask(()=>{
          // queueMicrotask 会重启一个微任务执行,需要判断status状态不是pending时,则不往下执行
          if(this.status !== PROMISE_STATUS_PENDING) return 
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value // 保存成功返回的值
          // console.log('resolve:',value)
          this.onFulfilledCallBack.forEach(fn=>{
            fn(this.value)
          })
        })
      }
     
    }
    const reject = (reason)=>{
      // 当状态为pending时 更改为失败状态
      if(this.status === PROMISE_STATUS_PENDING){
        // 建立一个微任务,保证promise.then先执行,才能调用到this.onRejected函数,否则报this.onRejected不是一个函数
        // 也可以使用setTimeout(宏任务),queueMicrotask 是 微任务,当前回合下就能执行
        queueMicrotask(()=>{
          // queueMicrotask 会重启一个微任务执行,需要判断status状态不是pending时,则不往下执行
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECT
          this.reason = reason // 保存失败返回的值
          this.onRejectCallBack.forEach(fn=>{
            fn(this.reason)
          })
        })
      }
    }
    try {

     executor(resolve,reject)
    }catch(err){
      console.log('errrrrrr:',err)
    }
  }

  then(onFulfilled,onRejected){
    // console.log('this.status:',onFulfilled)
    // 处理onRejected为undefined的时候
    const defaultOnRejected = (err)=>{throw err}
    onRejected = onRejected || defaultOnRejected

    // 处理onFulfilled为undefined的时候
    const defaultOnFulfilled = (value) => { return value }
    onFulfilled = onFulfilled || defaultOnFulfilled

    return new MyPromise((resolve,reject)=>{
       // 状态若是成功,则直接执行
      if(this.status === PROMISE_STATUS_FULFILLED){
        // 调用封装的try catch 函数
        execFnWithCatchError(onFulfilled,this.value,resolve,reject)
      }
      // 状态若是失败,则直接执行
      if(this.status === PROMISE_STATUS_REJECT){
         // 调用封装的try catch 函数
        execFnWithCatchError(onRejected,this.reason,resolve,reject)
      }
      // 将成功和失败回掉保存到callBack函数中
      if(this.status === PROMISE_STATUS_PENDING){
        if(onFulfilled) this.onFulfilledCallBack.push(()=>{
          // 调用封装的try catch 函数
          execFnWithCatchError(onFulfilled,this.value,resolve,reject)
        })
        if(onRejected) this.onRejectCallBack.push(()=>{
           // 调用封装的try catch 函数
          execFnWithCatchError(onRejected,this.reason,resolve,reject)
        })
      }
    })
  }

  // 增加 catch 方法
  catch(onRejected){
    // 可以直接调用then方法,把onFulfilled方法设置为undefined
    // 修改then方法,当onFulfilled为undefined时,返回一个throw err 报错,流程走到下一步
    return this.then(undefined,onRejected)
  }

  // 增加 finally 方法
  finally(onFinally){
    // 直接调用 then 方法
    this.then(()=>{
      onFinally()
    },()=>{
      onFinally()
    })
  }

  // 增加 resolve 方法
  static resolve(value){
    return new MyPromise(resolve=>{
      resolve(value)
    })
  }

  // 增加 static reject 方法
  static reject(reason){
      // new 当前自定义的类
      return new MyPromise((resolve,reject)=>{
        reject(reason)
      })
  }
  // 增加 static all 方法
  static all(promises){
    return new MyPromise((resolve,reject)=>{
      const values = []
      promises.forEach(item=>{
        item.then(res=>{
          values.push(res)
          if(values.length === promises.length){
            resolve(values)
          }
        }).catch(err=>{
          reject(err)
        })
      })
    })
  }
  // 增加 static allSettled 方法
 static allSettled(promises){
    return new MyPromise((resolve,reject)=>{
      const values = []
      promises.forEach(item=>{
        item.then(res=>{
          values.push({status:'fulfilled',value:res})
        }).catch(err=>{
          values.push({status:'rejected',value:err})
        })
      })
      resolve(values)
    })
  }

  // 增加 race 方法
   static race(promises){
    return new MyPromise((resolve,reject)=>{
      promises.forEach(item=>{
        item.then(res=>{
          resolve(res)
        }).catch(err=>{
          reject(err)
        })
      })
    })
  }
}

const promise = new MyPromise((resolve,reject)=>{
  resolve(44355)
  // reject(555)
  // throw new Error(' 直接 抛出 异常')
})
const promise1 = new MyPromise((resolve,reject)=>{
  resolve(443232)
  // reject(444)
  // throw new Error(' 直接 抛出 异常')
})
const promise2 = new MyPromise((resolve,reject)=>{
  // resolve(111)
  reject(444)
  // throw new Error(' 直接 抛出 异常')
})

MyPromise.race([promise,promise1,promise2]).then(res=>{
  console.log('all res:',res)
}).catch(err=>{
  console.log('all err:',err);
})

// MyPromise.resolve('this is a resolve').then(res=>{
//   console.log('res:',res)
// })

// MyPromise.reject('this is a reject').catch(res=>{
//   console.log('catch:',res)
// })

// promise.then(res=>{
//   console.log('res:',res)
// }).catch(err1=>{
//   console.log('catch err:',err1)
// }).finally(()=>{
//   console.log('finally')
// })

// promise.then(res=>{
//   console.log('res:',res)
//   throw new Error('err message')
// },err=>{
//   console.log('err:',err)
//   throw new Error('err message')
// }).then(res1=>{
//   console.log('res1:',res1)
// },err1=>{
//   console.log('err1:',err1)
// })

// promise.then(res=>{
//   console.log('res2:',res)
// },err=>{
//   console.log('err2:',err)
// })

// setTimeout(()=>{
//     promise.then(res=>{
//       console.log('res:',res)
//     })
// },3000)
相关推荐
a栋栋栋4 小时前
apifox
java·前端·javascript
请叫我飞哥@4 小时前
HTML 标签页(Tabs)详细讲解
前端·html
Anlici5 小时前
React18与Vue3组件通信对比学习(详细!建议收藏!!🚀🚀)
前端·vue.js·react.js
m0_748251525 小时前
PDF在线预览实现:如何使用vue-pdf-embed实现前端PDF在线阅读
前端·vue.js·pdf
中生代技术5 小时前
3.从制定标准到持续监控:7个关键阶段提升App用户体验
大数据·运维·服务器·前端·ux
m0_748239336 小时前
从零开始:如何在.NET Core Web API中完美配置Swagger文档
前端·.netcore
m0_748232926 小时前
【前端】Node.js使用教程
前端·node.js·vim
hawleyHuo6 小时前
umi 能适配 taro组件?
前端·前端框架
web130933203986 小时前
[JAVA Web] 02_第二章 HTML&CSS
java·前端·html
黑客呀7 小时前
Go Web开发之Revel - 网页请求处理流程
开发语言·前端·web安全·golang·系统安全