手写 Promise

whynotgonow 2020-05-16

const PENDING = ‘pending‘
const FULFILLED = ‘fulfilled‘
const REJECTED = ‘rejected‘
function MyPromise(executor) {
  let self = this
  self.value = null
  self.error = null
  self.status = PENDING
  // 异步 readFile 尚未 resolve 的时候先存储所有成功回调。
  // 即 thenable 方法中 status = PENDING 的时候先存储。
  // 待异步 readFile 执行到 resolve 时,status 改变然后依次执行 onFulfilledCallbacks 中的回调函数。
  self.onFulfilledCallbacks = []
  self.onRejectedCallbacks = []

  const resolve = (value) => {
    if (self.status !== PENDING) return; // res 或 rej 只走一条路径
    setTimeout(() => {
      self.status = FULFILLED
      self.value = value
      self.onFulfilledCallbacks.forEach((callback) => callback(self.value)) // 异步逻辑执行回调
    })
  }

  const reject = (error) => {
    if (self.status !== PENDING) return; // res 或 rej 只走一条路径
    setTimeout(() => {
      self.status = REJECTED
      self.error = error
      self.onRejectedCallbacks.forEach((callback) => callback(self.error)) // promise异步任务
    })
  }

  executor(resolve, reject)
}

// then 函数整体是一个同步进行的状态,遇到异步任务时,只有 this.status = PENDING
MyPromise.prototype.then = function (onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === ‘function‘ ? onFulfilled : value => value
  onRejected = typeof onRejected === ‘function‘ ? onRejected : error => { throw error }
  let bridgePromise;
  let self = this;
  // PENDING 时同步存储进回调数组 callbacks
  // 异步 readFile 时走 PENDING,因为同步执行到 then 时,readFile 尚未 resolve
  if (self.status === PENDING) {
    // return promise 可以放在 if else 的最层
    return bridgePromise = new MyPromise((resolve, reject) => { // new promise 立即执行
      self.onFulfilledCallbacks.push((value) => {
        try {
          let x = onFulfilled(value) // 拿到 then 中回调返回的结果?
          resolvePromise(bridgePromise, x, resolve, reject); // x 可能还是 promise
        } catch (e) {
          reject(e)
        }
      })
      self.onRejectedCallbacks.push((error) => {
        try {
          let x = onRejected(error);
          // 假若 x 还是一个 promise,不能直接 resolve
          resolve(x);
        } catch (e) {
          reject(e);
        }
      });
    })

  } else if (this.status === FULFILLED) { // 同步执行走到 FULFILLED
    return bridgePromise = new MyPromise((resolve, reject) => {
      try {
        let x = onFulfilled(self.value)
        resolvePromise(bridgePromise, x, resolve, reject)
      } catch (e) {
        reject(e)
      }
    })
  } else {
    return bridgePromise = new MyPromise((resolve, reject) => {
      try {
        let x = onRejected(self.error)
        resolvePromise(bridgePromise, x, resolve, reject)
      } catch (e) {
        reject(e)
      }
    })
  }
}

MyPromise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected)
}

// finally 本质上是一个 then 方法
// 入参 callback 是一个函数,需要在 then 中执行
// 使用 Promise.resolve 会等 callback() 函数执行完后再返回结果,并将上一个 then 的 value 返回
MyPromise.prototype.finally = function (callback) {
  // this 即上一个 promise
  return this.then(value => {
    return MyPromise.resolve(callback()).then(() => value)
  }, error => {
    return MyPromise.resolve(callback()).then(() => {
      throw error;
    })
  })
}

MyPromise.resolve = function (callback) {
  // MyPromise.resolve 的职责就是返回一个 promise 对象,显然已经达到,故直接返回
  if (callback instanceof MyPromise) return callback;
  return new MyPromise((resolve, reject) => {
    if (callback.then && typeof callback.then === ‘function‘) {
      callback.then(resolve, reject)
    } else {
      resolve(callback)
    }
  })
}

MyPromise.reject = function (reason) {
  return new MyPromise((resolve, reject) => {
    reject(reason)
  })
}

MyPromise.all = function (promises) {
  return new MyPromise((resolve, reject) => {
    let len = promises.length
    let result = []
    let index = 0
    if (len === 0) return resolve(resutl);
    for (let i = 0; i < len; i++) {
      // 统一转成 promise 对象处理
      MyPromise.resolve(promises[i]).then(res => {
        result[i] = res
        index++;
        if (index === len) resolve(result);
      }).catch(err => {
        reject(err);
      })
    }
  })
}

MyPromise.race = function (promises) {
  return new MyPromise((resolve, reject) => {
    let len = promises.length
    if (len === 0) return;
    for (let i = 0; i < len; i++) {
      MyPromise.resolve(promises[i]).then(data => {
        resolve(data)
        return;
      }).catch(err => {
        reject(err)
        return;
      })
    }
  })
}


function resolvePromise(bridgePromise, x, resolve, reject) {
  if (x instanceof MyPromise) {
    if (x.status === PENDING) {
      x.then(y => {
        resolvePromise(bridgePromise, y, resolve, reject)
      }, error => {
        reject(error)
      })
    } else {
      x.then(resolve, reject)
    }
  } else {
    resolve(x)
  }
}

let fs = require(‘fs‘)
let readFilePromise = (filename) => {
  return new MyPromise((resolve, reject) => {
    fs.readFile(filename, (err, data) => {
      if (!err) {
        resolve(data)
      } else {
        reject(err)
      }
    })
  })
}
readFilePromise(‘./p6.html‘).then(data => {
  console.log(‘1_p6.html‘)
  return readFilePromise(‘./p6.html‘)
}).then(data => {
  console.log(‘2_p6.html‘)
})

相关推荐