Promise原理

v1

仅能处理异步的成功和失败

实现

// no-log
// 自定义函数`Promi`来模拟`Promise`
function ProMi(executor) {
  let that = this
  that.status = 'pending'
  that.failCallBack = undefined
  that.successCallback = undefined
  executor(resolve.bind(that), reject.bind(that))

  function resolve(params) {
    if (that.status === 'pending') {
      that.status = 'success'
      if (that.successCallback) {
        that.successCallback(params)
      } else {
        console.error('未传入成功回调')
      }
    }
  }

  function reject(params) {
    if (that.status === 'pending') {
      that.status = 'fail'
      if (that.failCallBack) {
        that.failCallBack(params)
      } else {
        console.error('未传入失败回调')
      }
    }
  }
}

ProMi.prototype.then = function (successCallback, failCallBack) {
  this.successCallback = successCallback
  this.failCallBack = failCallBack
}

测试一下Promi

new ProMi(function (resolve, reject) {
  setTimeout(() => {
    resolve('{"msg": "Hello world!"}')
  }, 1000)
}).then((data) => {
  // log-async
  console.log(data)
}, null)

// 由于 try catch只能捕捉同步方法的错误,这里假装有错误
new ProMi(function (resolve, reject) {
  setTimeout(() => {
    reject('{"msg": "我是一个一个错误"}')
  }, 1000)
}).then(null, (err) => {
  // log-async
  console.log(err)
})

这便是,Promise的最基本原理。

bug

但是当我们使用如下同步代码测试时,发现并不凑效(报错:未传入成功/失败回调,需要查看控制台)

new ProMi(function (resolve, reject) {
  // 这是一段同步代码
  let sum = 0
  for (let i = 0; i < 10000; i++) {
    sum = sum + i
  }
  resolve(sum)
}).then((data) => {
  // 不走这,因为没有传入成功的回调函数
  // log-async
  console.log(data)
})
new ProMi(function (resolve, reject) {
  // 这是一段同步代码
  try {
    abc.alert(1)
  } catch (e) {
    reject(e.message)
  }
}).then(null, (err) => {
  // 不走这,因为没有失败的回调函数
  // log-async
  console.log(err)
})

v2

能处理异步+同步的成功和失败

实现

对于同步方法,failCallBack不能及时传入,此时只需要修改下 resolve 和 reject

function ProMise(executor) {
  let that = this
  that.status = 'pending'
  that.failCallBack = undefined
  that.successCallback = undefined
  that.error = undefined
  executor(resolve.bind(that), reject.bind(that))

  function resolve(params) {
    if (that.status === 'pending') {
      that.status = 'success'
      if (that.successCallback) {
        that.successCallback(params)
      } else {
        // log-async
        console.log('未第一时间传入成功回调,若干毫秒后将重试')
        setTimeout(() => {
          that.successCallback(params)
        }, 1)
      }
    }
  }

  function reject(params) {
    if (that.status === 'pending') {
      that.status = 'fail'
      if (that.failCallBack) {
        that.failCallBack(params)
      } else {
        // log-async
        console.log('未第一时间传入失败回调,若干毫秒后将重试')
        setTimeout(() => {
          that.failCallBack(params)
        }, 1)
      }
    }
  }
}

ProMise.prototype.then = function (full, fail) {
  this.successCallback = full
  this.failCallBack = fail
}
window.ProMise = ProMise

// 再测试一遍同步回调
new ProMise(function (resolve, reject) {
  try {
    abc.alert(1)
  } catch (e) {
    reject(e.message)
  }
}).then(null, (err) => {
  // log-async
  console.log(err)
})

new ProMise(function (resolve, reject) {
  let start = new Date().getTime()
  let sum = 0
  for (let i = 0; i < 3000 * 3000; i++) {
    sum = sum + i
  }
  let end = new Date().getTime()
  // log-async
  console.log(end - start)
  resolve(sum)
}).then(data => {
  // log-async
  console.log(data)
})
posted @ 2020-08-31 14:50  oceans-pro  阅读(210)  评论(0编辑  收藏  举报