一文明白如何封装一个Promise函数

93 阅读1分钟

大家好,我是右子。

大家是不是在面试的时候有被要求手写一个promise?我们来看一下如何自定义一个promise。

一般这种题,可以用倒推的形式进行,我们来看一下promise是如何书写的。

let status = "";
let p1 = new Promise((resolve,reject)=>{
    if(status==="ok"){
        resolve("success");
    }else if(status==="errno"){
        resolve("errno");
    }else{
        reject();
    }
});
p1.then(resp=>{
    console.log(resp);
});

由此我们来封装一下简版

class MyPromise{
    constructor(fn){
        this.status = "pending"; // fulfilled、rejected、pending
        this.resolved = null;
        this.rejected = null;
        fn && fn(this.resolve.bind(this),this.reject.bind(this))
    }
    then(cb){
        cb && cb(this.resolved);
    }
    catch(cb){
        cb && cb(this.rejected);
    }
    resolve(resp){
        this.resolved = resp;
        this.status = "fulfilled";
    }
    reject(resp){
        this.rejected = resp;
        this.status = "rejected";
    }
}

let status = "";
let mp1 = new MyPromise((resolve,reject)=>{
    if(status==="ok"){
        resolve("success");
    }else if(status==="errno"){
        resolve("errno");
    }else{
        reject("异常");
    }
});
mp1.then(resp=>{
    console.log("ok callback");
})

实现一个 Promise

function MyPromise(executor) {
  let self = this
  self.status = 'pending'
  self.data = undefined
  self.onResolvedCallback = []
  self.onRejectedCallback = []

  function resolve(value) {
    if (self.status === 'pending') {
      self.status = 'resolved'
      self.data = value
      for (let i = 0; i < self.onResolvedCallback.length; i++) {
        self.onResolvedCallback[i](value)
      }
    }
  }

  function reject(reason) {
    if (self.status === 'pending') {
      self.status = 'rejected'
      self.data = reason
      for (let i = 0; i < self.onRejectedCallback.length; i++) {
        self.onRejectedCallback[i](reason)
      }
    }
  }

  try {
    executor(resolve, reject)
  } catch (error) {
    reject(error)
  }
}

MyPromise.prototype.then = function (onResolved, onRejected) {
  let self = this
  let promise2

  onResolved = typeof onResolved === 'function' ? onResolved : function (v) { return v }
  onRejected = typeof onRejected === 'function' ? onRejected : function (r) { throw r }

  if (self.status === 'resolved') {
    return promise2 = new MyPromise(function (resolve, reject) {
      try {
        let x = onResolved(self.data)
        if (x instanceof MyPromise) {
          x.then(resolve, reject)
        }
        resolve(x)
      } catch (error) {
        reject(error)
      }
    })
  }

  if (self.status === 'rejected') {
    return promise2 = new MyPromise(function (resolve, reject) {
      try {
        let x = onRejected(self.data)
        if (x instanceof MyPromise) {
          x.then(resolve, reject)
        }
      } catch (error) {
        reject(error)
      }
    })
  }

  if (self.status === 'pending') {
    return promise2 = new MyPromise(function (resolve, reject) {
      self.onResolvedCallback.push(function (value) {
        try {
          let x = onResolved(self.data)
          if (x instanceof MyPromise) {
            x.then(resolve, reject)
          }
        } catch (error) {
          reject(error)
        }
      })

      self.onRejectedCallback.push(function (reason) {
        try {
          let x = onRejected(self.data)
          if (x instanceof MyPromise) {
            x.then(resolve, reject)
          }
        } catch (error) {
          reject(error)
        }
      })
    })
  }
}

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