手写promise

1 代码实现 

/*
自定义Promise
 */

(function (window) {

  /*
  Promise构造函数
  excutor: 内部同步执行的函数  (resolve, reject) => {}
   */
  function Promise(excutor) {

    const self = this
    self.status = 'pending' // 状态值, 初始状态为pending, 成功了变为resolved, 失败了变为rejected
    self.data = undefined // 用来保存成功value或失败reason的属性
    self.callbacks = [] // 用来保存所有待调用的包含onResolved和onRejected回调函数的对象的数组

    /*
    异步处理成功后应该调用的函数;value: 将交给onResolve()的成功数据
     */
    function resolve(value) {
      // 如果当前不是pending, 直接结束
      if(self.status!==pending) { 
        return
      }

      // 立即更新状态, 保存数据
      self.status = 'resolved'
      self.data = value

      // 如果有待执行的callback函数,立即异步执行回调函数onResolved
      if (self.callbacks.length > 0) {
        setTimeout(() => {
          self.callbacks.forEach(obj => {
            obj.onResolved(value)
          })
        })
      }
    }

    /*
    异步处理失败后应该调用的函数;reason: 将交给onRejected()的失败数据
     */
    function reject(reason) {
      // 如果当前不是pending, 直接结束
      if(self.status!==pending) { 
        return
      }
      
      // 立即更新状态, 保存数据
      self.status = 'rejected'
      self.data = reason

      // 如果有待执行的callback函数,立即异步执行回调函数onRejected
      if (self.callbacks.length > 0) {
        setTimeout(() => {
          self.callbacks.forEach(obj => {
            obj.onRejected(value)
          })
        })
      }
    }

    try {// 立即同步调用excutor()处理
      excutor(resolve, reject)
    } catch (error) { // 如果出了异常, 直接失败
      reject(error)
    }
  }

  /*
  1.为promise指定成功/失败的回调函数;函数的返回值是一个新的promise对象
   */
  Promise.prototype.then = function (onResolved, onRejected) {

    // 保存promise对象
    const self = this

    // 如果成功/失败的回调函数不是function, 指定一个默认实现的函数
    onResolved = typeof onResolved === 'function' ? onResolved : value => value//向后传递成功的value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}//向后传递失败的reason(实现错误传透)

    // 返回一个新的promsie对象:三种状态
    return new Promise((resolve, reject) => {
      // 调用指定的回调函数,根据执行结果改变return的promise的状态/数据
      function handle (callback) {
        try {
            const x = callback(self.data)// 用x变量存储onResolved()的返回值
            //a.如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
            if (x instanceof Promise) {
              x.then(resolve, reject)
            //b.如果回调函数返回的不是promise,return的promise会成功,返回value
            } else {
              resolve(x)
            }
            //c. 如果抛出异常,return的promise就会失败,reason就是error
        } catch (error) {
            reject(error)
        }
      }
      if (self.status === 'resolved') {
        // 异步执行onResolved
        setTimeout(() => {
          handle(onResolved)
        })
      } else if (self.status === 'rejected') {
        // 异步执行onRejected
        setTimeout(() => {
          handle(onRejected)
        })
      } else {
        // 保存待处理的回调函数
        self.callbacks.push({
          onResolved (value) {
            handle(onResolved)
          },

          onRejected(value) {
            handle(onRejected)
          }
        })
      }
    })
  }

  /*
  2.为promise指定失败的回调函数;是then(null, onRejected)的语法糖
   */
  Promise.prototype.catch = function (onRejected) {
    return this.then(null, onRejected)
  }

  /*
  3.返回一个指定了成功value的promise对象;value: 一般数据或promise
   */
  Promise.resolve = function (value) {
    return new Promise((resolve, reject) => {
      // 如果传入的是promise对象, 将此promise的结果值作为返回promise的结果值
      if (value instanceof Promise) { 
        value.then(resolve, reject)//结果需要通过then取到
      // 将value作为返回promise的成功结果值
      } else { 
        resolve(value)
      }
    })
  }

  /*
  4.返回一个指定了失败reason的promise对象;reason: 一般数据/error
   */
  Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
      // 将传入的参数作为返回promise的失败结果值
      reject(reason)
    })
  }

  /*
  5.返回一个新的promise对象, 只有promises中所有promise都产生成功value时, 才最终成功, 只要有一个失败就直接失败
   */
  Promise.all = function (promises) {
    // 返回一个新的promise
    return new Promise((resolve, reject) => {
      // 已成功的数量
      let resolvedCount = 0
      // 待处理的promises数组的长度
      const promisesLength = promises.length
      // 准备一个保存成功值的数组(保证结果按照数组的顺序)
      const values = new Array(promisesLength)
      // 遍历每个待处理的promise
      for (let i = 0; i < promisesLength; i++) {
        // promises中元素可能不是一个promise, 需要用resolve包装一下
        Promise.resolve(promises[i]).then(
          value => {
            // 成功当前promise成功的值到对应的下标
            values[i] = value
            // 成功的数量加1
            resolvedCount++
            // 一旦全部成功
            if(resolvedCount===promisesLength) {
              // 将所有成功值的数组作为返回promise对象的成功结果值
              resolve(values)
            }
          },
          reason => {
            // 一旦有一个promise产生了失败结果值, 将其作为返回promise对象的失败结果值
            reject(reason)
          }
        )
      }
    })
  }

  /*
  6.返回一个 promise,一旦某个promise解决或拒绝, 返回的 promise就会解决或拒绝。
  */
  Promise.race = function (promises) {
    // 返回新的promise对象
    return new Promise((resolve, reject) => {
      // 遍历所有promise
      for (var i = 0; i < promises.length; i++) {
        Promise.resolve(promises[i]).then(
          (value) => { // 只要有一个成功了, 返回的promise就成功了
            resolve(value)
          },
          (reason) => { // 只要有一个失败了, 返回的结果就失败了
            reject(reason)
          }
        )
      }
    })
  }

  /* 
  7.返回一个延迟指定时间才确定结果的promise对象
  */
  Promise.resolveDelay = function (value, time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (value instanceof Promise) { // 如果value是一个promise, 取这个promise的结果值作为返回的promise的结果值
          value.then(resolve, reject) // 如果value成功, 调用resolve(val), 如果value失败了, 调用reject(reason)
        } else {
          resolve(value)
        }
      }, time);
    })
  }

  /*
  8.返回一个延迟指定时间才失败的Promise对象。
  */
  Promise.rejectDelay = function (reason, time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(reason)
      }, time)
    })
  }

  // 暴露构造函数
  window.Promise = Promise
})(window)

2 逻辑分析 

Promise:

  • 同步调用excutor,用try-catch处理。
  • 调用resolve,更新状态并保存数据,异步执行回调函数onResolved。
  • 调用reject,执行的是onRejected

Promise.prototype.then:

  • 根据status,来决定是保存还是调用异步回调函数。
  • 根据回调函数的返回结果,返回新的promise对象。

        a.如果回调函数返回的是promise,return的promise的结果就是这个promise的结果

        b.如果回调函数返回的不是promise,return的promise会成功,返回value

        c. 如果抛出异常,return的promise就会失败,reason就是error

Promise.prototype.catch:

是then(null, onRejected)的语法糖

Promise.resolve:

  • 如果传入的是promise对象, 将此promise的结果值作为返回promise的结果值
  • 如果传入的是非promise对象, 将value作为返回promise的成功结果值

Promise.reject:

将传入的参数作为返回promise的失败结果值

Promise.all:

遍历每个待处理的promises,成功将value存到到对应的下标,直到全部成功返回value;失败将reason返回。

Promise.race:

遍历每个待处理的promises,只要有一个成功了, 返回的promise就成功了;只要有一个失败了, 返回的结果就失败了

3 class版本

excutor定义改成constructor

原型上的直接定义方法,类上的加static

/*
  自定义Promise构造函数模块
*/
(function (window) {

  class Promise {
    constructor (excutor) {
      const self = this

      // 1. 初始化属性
      self.status = 'pending' 
      self.data = undefined 
      self.callbacks = [] 

      // 2. 定义resolve和reject两个函数
      /*
      当异步处理成功后应该立即执行的函数
      value: 需要传递给onResolved函数的成功的值
      内部:
        1. 同步修改状态和保存数据
        2. 异步调用成功的回调函数
       */
      function resolve(value) {

        if (self.status !== 'pending') { 
          return
        }

        // 1. 同步修改状态和保存数据
        self.status = 'resolved'
        self.data = value
        // 2. 异步调用成功的回调函数
        setTimeout(() => {
          self.callbacks.forEach(obj => {
            obj.onResolved(value)
          })
        })
      }

      /*
      当异步处理失败/异常时后应该立即执行的函数
      reason: 需要传递给onRejected函数的失败的值
      内部:
        1. 同步修改状态和保存数据
        2. 异步调用失败的回调函数
       */
      function reject(reason) {

        if (self.status !== 'pending') {
          return
        }

        // 1. 同步修改状态和保存数据
        self.status = 'rejected'
        self.data = reason
        // 2. 异步调用失败的回调函数
        setTimeout(() => {
          self.callbacks.forEach(obj => {
            obj.onRejected(reason)
          })
        })
      }

      // 3. 执行excutor,并传入定义好的resolve和reject两个函数
      try {
        excutor(resolve, reject)
      } catch (error) { // 如果excutor函数中抛出异常, 当前promise失败
        reject(error)
      }

    }

    /*
      指定成功和失败后回调函数
      函数的返回值是一个新的promise
    */
    then (onResolved, onRejected) {
      const self = this

      // 如果onResolved/onRejected不是函数, 可它指定一个默认的函数
      onResolved = typeof onResolved === 'function' ? onResolved : value => value // 指定返回的promise为一个成功状态, 结果值为 value
      onRejected = typeof onRejected === 'function' ? onRejected : reason => {
        throw reason
      } // 指定返回的promise为一个失败状态, 结果值为reason

      // 返回一个新的promise对象
      return new Promise((resolve, reject) => {

        /* 
        专门抽取的用来处理promise成功/失败结果的函数
        callback: 成功/失败的回调函数
        */
        function handle(callback) {
          // 1. 抛出异常  ===> 返回的promise变为rejected
          try {
            const x = callback(self.data)
            // 2. 返回一个新的promise ===> 得到新的promise的结果值作为返回的promise的结果值
            if (x instanceof Promise) {
              x.then(resolve, reject) // 一旦x成功了, resolve(value), 一旦x失败了: reject(reason)
            } else {
              // 3. 返回一个一般值(undefined) ===> 将这个值作为返回的promise的成功值
              resolve(x)
            }
          } catch (error) {
            reject(error)
          }
        }

        if (self.status === 'resolved') { // 当前promise已经成功了
          setTimeout(() => {
            handle(onResolved)
          })
        } else if (self.status === 'rejected') { // 当前promise已经失败了
          setTimeout(() => {
            handle(onRejected)
          })
        } else { // 当前promise还未确定 pending
          // 将onResolved和onRejected保存起来
          self.callbacks.push({
            onResolved(value) {
              handle(onResolved)
            },
            onRejected(reason) {
              handle(onRejected)
            }
          })
        }
      })
    }
    

    /*
      方法返回一个Promise,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同
      then()的语法糖
    */
    catch (onRejected) {
      return this.then(null, onRejected)
    }

    /*
      返回一个以给定值解析后的Promise 对象
      value也可能是一个promise
    */
    static resolve (value) {
      return new Promise((resolve, reject) => {
        if (value instanceof Promise) { // 如果value是一个promise, 取这个promise的结果值作为返回的promise的结果值
          value.then(resolve, reject) // 如果value成功, 调用resolve(val), 如果value失败了, 调用reject(reason)
        } else {
          resolve(value)
        }
      })
    }

    /* 
      返回一个延迟指定时间才确定结果的promise对象
    */
    static resolveDelay (value, time) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (value instanceof Promise) { // 如果value是一个promise, 取这个promise的结果值作为返回的promise的结果值
            value.then(resolve, reject) // 如果value成功, 调用resolve(val), 如果value失败了, 调用reject(reason)
          } else {
            resolve(value)
          }
        }, time);
      })
    }

    /*
      返回一个带有拒绝原因reason参数的Promise对象。
    */
    static reject (reason) {
      return new Promise((resolve, reject) => {
        reject(reason)
      })
    }

    /*
      返回一个延迟指定时间才失败的Promise对象。
    */
    static rejectDelay = function (reason, time) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          reject(reason)
        }, time)
      })
    }

    /*
      返回一个 Promise 实例
      只有当promises中所有的都成功了, 返回的promise才成功, 只要有一个失败, 返回的promise就失败了
    */
    static all (promises) {
      return new Promise((resolve, reject) => {

        let resolvedCount = 0 // 用来保存已成功的个数
        const promisesLength = promises.length // 所有待处理promise个数
        const values = new Array(promisesLength) // 存储所有成功value的数组
        promises.forEach((p, index) => {
          (function (index) {
            // promises中元素可能不是promise对象, 需要用resolve()包装一下
            Promise.resolve(p).then(
              value => {
                values[index] = value // 保存到values中对应的下标
                resolvedCount++
                // 如果全部成功了, resolve(values)
                if (resolvedCount === promisesLength) {
                  resolve(values)
                }
              },
              reason => {
                // 只要一个失败了, reject(reason)
                reject(reason)
              }
            )
          })(index)
        })
      })
    }

    /*
      返回一个 promise,一旦某个promise解决或拒绝, 返回的 promise就会解决或拒绝。
    */
    static race (promises) {
      return new Promise((resolve, reject) => {// 返回新的promise对象
        for (var i = 0; i < promises.length; i++) {// 遍历所有promise
          Promise.resolve(promises[i]).then(
            (value) => { // 只要有一个成功了, 返回的promise就成功了
              resolve(value)
            },
            (reason) => { // 只要有一个失败了, 返回的结果就失败了
              reject(reason)
            }
          )
        }
      })
    }
  }

  // 向外暴露Promise
  window.Promise = Promise
})(window)

4 其他编码

4.1 加载图片

function loadImg(src) {
    const p = new Promise(
        (resolve, reject) => {
            const img = document.createElement('img')
            img.onload = () => {
                resolve(img)
            }
            img.onerror = () => {
                const err = new Error(`图片加载失败 ${src}`)
                reject(err)
            }
            img.src = src
        }
    )
    return p
}

const url1 = 'https://img.mukewang.com/5a9fc8070001a82402060220-140-140.jpg'
const url2 = 'https://img3.mukewang.com/5a9fc8070001a82402060220-100-100.jpg'

//then/catch
loadImg(url1).then(img1 => {
    console.log(img1.width)
    return img1 // 普通对象
}).then(img1 => {
    console.log(img1.height)
    return loadImg(url2) // promise 实例
}).then(img2 => {
    console.log(img2.width)
    return img2
}).then(img2 => {
    console.log(img2.height)
}).catch(ex => console.error(ex))

//async/await
!(async function(){
    const img1=await loadImg(url1)
    console.log(img1.height,img1.width)

    const img2=await loadImg(url2)
    console.log(img2.height,img2.width)
})()

4.2 读取文件

function getFile(fpath) {
    const p = new Promise(
        (resolve, reject) => {
            fs.readFile(fpath,'utf8',(err,data)=>{
                if(err) return reject(err)
                resolve(data)
            })
        }
    )
    return p
}

//then/catch
getFile(url1).then(r1=> {
    console.log(r1)
}).catch(ex => console.log(ex.message))

//async/await
!(async function(){
    const r1=await getFile(url1)
    console.log(r1)

    const r2=await getFile(url2)
    console.log(r2)
})()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值