Promise详解-手写

0 阅读7分钟

初始化

我们知道Promise内部有三种状态,因此我们定义status:

const FULFILLED = 'fullfilled'
const REJECTED = 'rejected'
const PENDING = 'pending'

class Promise{
  status = PENDING
}

其次,在Promise兑现和拒绝的时候,需要有变量来存储值,也就是then()中回调可以接收的值。then((res)=>{})的这个res

const FULFILLED = 'fullfilled'
const REJECTED = 'rejected'
const PENDING = 'pending'

class Promise{
  status = PENDING
  value = undefined
  reason = undefined
}

接下来我们思考构造函数,我们考虑new Promise(executor), 这里会接收executor,excutor是什么形式呢?(resolve,reject)=> {}, 其中resolve和reject是可以改变Promise状态的函数,可以给Promise调用。因此我们考虑写出以下代码:

const FULFILLED = 'fullfilled'
const REJECTED = 'rejected'
const PENDING = 'pending'

class Promise{
  status = PENDING
  value = undefined
  reason = undefined

  construct(executor){
    const reject = (val) => {
      this.status = REJECTED
      this.value = val
    }
    const resolve = (reason) => {
      this.status = FULFILLED
      this.reason = reason
    }
    try{
      // 从这里我们可以知道new Promise(executor)中的executor是同步代码,会执行一次
      executor(resolve, reject)
    }catch(e){
      reject(e)
    }
  }
}

然后我们考虑实现then方法,then(onFulfilled, onRejected), MDN上的解释如下:

onFulfilled 可选一个在此 Promise 对象被兑现时异步执行的函数。它的返回值将成为 then() 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数:

valuePromise 对象的兑现值。

如果 onFulfilled 不是一个函数,则内部会被替换为一个恒等函数((x) => x),它只是简单地将兑现值向前传递。

onRejected 可选一个在此 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 catch() 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数:

reasonPromise 对象被拒绝的原因。

如果 onRejected 不是一个函数,则内部会被替换为一个抛出器函数((x) => { throw x; }),它会抛出它收到的拒绝原因

同时我们需要明确,then的返回是一个新的promise,因此我们有以下实现:

const FULFILLED = 'fullfilled'
const REJECTED = 'rejected'
const PENDING = 'pending'

class Promise{
  status = PENDING
  value = undefined
  reason = undefined

  construct(executor){
    const reject = (val) => {
      this.status = REJECTED
      this.value = val
    }
    const resolve = (reason) => {
      this.status = FULFILLED
      this.reason = reason
    }
    try{
      // 从这里我们可以知道new Promise(executor)中的executor是同步代码,会执行一次
      executor(resolve, reject)
    }catch(e){
      reject(e)
    }
  }
  
  then(onFulfilled, onRejected){
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (x) => (x)
    onRejected = typeof onRejected === 'function' ? onRejected : (x) => { throw x }
    return new Promise((resolve, reject)=>{
    })
  }
}

then中的回调是在Promise发生改变的时候会调用的,因此我们肯定是要在Promise中判断相关的状态,我们补全这块代码,针对每种状态填写相应的逻辑,对于新的返回的新的Promise,我们也需要变更它的状态,因此有以下代码:

const FULFILLED = 'fullfilled'
const REJECTED = 'rejected'
const PENDING = 'pending'

class Promise{
  status = PENDING
  value = undefined
  reason = undefined

  construct(executor){
    const reject = (val) => {
      this.status = REJECTED
      this.value = val
    }
    const resolve = (reason) => {
      this.status = FULFILLED
      this.reason = reason
    }
    try{
      // 从这里我们可以知道new Promise(executor)中的executor是同步代码,会执行一次
      executor(resolve, reject)
    }catch(e){
      reject(e)
    }
  }

  then(onFulfilled, onRejected){
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (x) => (x)
    onRejected = typeof onRejected === 'function' ? onRejected : (x) => { throw x }
    // 既然我们需要知道当前Promise的状态,我们就需要保存一个this变量
    const self = this
    return new Promse((resolve, reject)=> {
      if(self.status === PENDING){
        // 此时调用then的promise还未完成,因此需要将回调保存到队列中
      }else if(self.status === FULFILLED){
        // 此时调用then的promise已经完成,可以执行回调
      }else if(self.status === REJECTED){
        // 此时调用then的promise已经为拒绝状态,可以执行回调
      }
    })
  }
}

从注释代码中我们可以知道,当PENDING的时候,我们需要保存这些回调函数,那么这些回调函数会在什么时候执行呢?在exectuor调用resolve()/reject()的时候,我们需要执行这些回调函数。所以在这之前,我们需要有地方能够存储这些回调。然后在resolve和reject的时候执行这些回调。

const FULFILLED = 'fullfilled'
const REJECTED = 'rejected'
const PENDING = 'pending'

class Promise{
  status = PENDING
  value = undefined
  reason = undefined
  resolvedCallbacks = []
  rejectedCallbacks = []  

  construct(executor){
    const reject = (reason) => {
      this.status = REJECTED
      this.reason = reason
      if(rejectedCallbacks.length > 0){
        setTimeout(()=>{
          rejectedCallbacks.forEach((callback)=>{
            callback(this.reason)
          })
        })
      }
    }
    const resolve = (val) => {
      this.status = FULFILLED
      this.value = val
      if(resolvedCallbacks.length > 0){
        setTimeout(()=>{
          resolvedCallbacks.forEach((callback)=>{
            callback(this.value)
          })
        })
      }
    }
    try{
      // 从这里我们可以知道new Promise(executor)中的executor是同步代码,会执行一次
      executor(resolve, reject)
    }catch(e){
      reject(e)
    }
  }

  then(onFulfilled, onRejected){
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (x) => (x)
    onRejected = typeof onRejected === 'function' ? onRejected : (x) => { throw x }
    // 既然我们需要知道当前Promise的状态,我们就需要保存一个this变量
    const self = this
    return new Promse((resolve, reject)=> {
      if(self.status === PENDING){
        // 此时调用then的promise还未完成,因此需要将回调保存到队列中
      }else if(self.status === FULFILLED){
        // 此时调用then的promise已经完成,可以执行回调
      }else if(self.status === REJECTED){
        // 此时调用then的promise已经为拒绝状态,可以执行回调
      }
    })
  }
}

我们需要思考如何把回调函数推进callbacks数组中,我们不能直接把onFulfilled和onRejcted推进数组中,因为then返回的Promise的状态也需要改变,如果我们直接使用onFulfilled和onRejected,那么返回的then返回的Promise的状态可能一直都是PENDING的,无法被改变,因此我们需要一层包装函数,接受then返回的Promise中的resolve和reject,以此达到改变新Promise状态的目的。因此我们可以有以下实现:

// 只写then方法部分
then(onFulfilled, onRejected){
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (x) => (x)
    onRejected = typeof onRejected === 'function' ? onRejected : (x) => { throw x }
    // 既然我们需要知道当前Promise的状态,我们就需要保存一个this变量
    const self = this
    return new Promse((resolve, reject)=> {
    const handleFulfilled = (value) => {
      try{
        let res = onFulfilled(value)
        resolve(res)
      }catch(e){
        reject(e)
      }
    }

    const handleRejected = (reason) => {
      try{
        let res = onRejected(reason)
        resolve(res)
      }catch(e){
        reject(e)
      }
    }

    if(self.status === PENDING){
        // 此时调用then的promise还未完成,因此需要将回调保存到队列中
        this.resolvedCallbacks.push(handleFulfilled)
        this.rejectedCallbacks.push(handleRejected)
      }else if(self.status === FULFILLED){
        // 此时调用then的promise已经完成,可以执行回调
        setTimeout(()=>handleFulfilled(this.value))
      }else if(self.status === REJECTED){
        // 此时调用then的promise已经为拒绝状态,可以执行回调
        setTimeout(()=>handleRejected(this.reason))
      }
    })
 }

至此的话,简单的实现就差不多了,还差最后的关键,如果then中的回调返回的是一个Promise,我们该如何处理,then(()=>new Promise()).then(xxx)这种情况下,我们需要等待前一个then中的Promise完成,才能够执行下一个then。例子中()=>new Promise(),这个新建的Promise也就是我们onFulfilled方法的返回,也就是res。因此我们需要判断这个res是否为Promise,如果是Promise,需要等待这个Promise完成。

// 只写then方法部分
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (x) => x;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (x) => {
            throw x;
          };
    // 既然我们需要知道当前Promise的状态,我们就需要保存一个this变量
    const self = this;
    return new Promse((resolve, reject) => {
      const handleFulfilled = (value) => {
        try {
          let res = onFulfilled(value);
          if (res instanceof Promise) {
            // 将我们现在的resovle和reject传递下去
            res.then(resolve, reject);
          } else {
            resolve(res);
          }
        } catch (e) {
          reject(e);
        }
      };

      const handleRejected = (reason) => {
        try {
          let res = onRejected(reason);
          if (res instanceof Promise) {
            res.then(resolve, reject);
          } else {
            resolve(res);
          }
        } catch (e) {
          reject(e);
        }
      };

      if (self.status === PENDING) {
        // 此时调用then的promise还未完成,因此需要将回调保存到队列中
        this.resolvedCallbacks.push(handleFulfilled);
        this.rejectedCallbacks.push(handleRejected);
      } else if (self.status === FULFILLED) {
        // 此时调用then的promise已经完成,可以执行回调
        setTimeout(() => handleFulfilled(this.value));
      } else if (self.status === REJECTED) {
        // 此时调用then的promise已经为拒绝状态,可以执行回调
        setTimeout(() => handleRejected(this.reason));
      }
    });
  }

完整代码:

const FULFILLED = "fullfilled";
const REJECTED = "rejected";
const PENDING = "pending";

class Promise {
  status = PENDING;
  value = undefined;
  reason = undefined;
  resolvedCallbacks = [];
  rejectedCallbacks = [];

  construct(executor) {
    const reject = (reason) => {
      this.status = REJECTED;
      this.reason = reason;
      if (rejectedCallbacks.length > 0) {
        setTimeout(() => {
          rejectedCallbacks.forEach((callback) => {
            callback(this.reason);
          });
        });
      }
    };
    const resolve = (val) => {
      this.status = FULFILLED;
      this.value = val;
      if (resolvedCallbacks.length > 0) {
        setTimeout(() => {
          resolvedCallbacks.forEach((callback) => {
            callback(this.value);
          });
        });
      }
    };
    try {
      // 从这里我们可以知道new Promise(executor)中的executor是同步代码,会执行一次
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }

  // 只写then方法部分
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (x) => x;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (x) => {
            throw x;
          };
    // 既然我们需要知道当前Promise的状态,我们就需要保存一个this变量
    const self = this;
    return new Promse((resolve, reject) => {
      const handleFulfilled = (value) => {
        try {
          let res = onFulfilled(value);
          if (res instanceof Promise) {
            // 将我们现在的resovle和reject传递下去
            res.then(resolve, reject);
          } else {
            resolve(res);
          }
        } catch (e) {
          reject(e);
        }
      };

      const handleRejected = (reason) => {
        try {
          let res = onRejected(reason);
          if (res instanceof Promise) {
            res.then(resolve, reject);
          } else {
            resolve(res);
          }
        } catch (e) {
          reject(e);
        }
      };

      if (self.status === PENDING) {
        // 此时调用then的promise还未完成,因此需要将回调保存到队列中
        this.resolvedCallbacks.push(handleFulfilled);
        this.rejectedCallbacks.push(handleRejected);
      } else if (self.status === FULFILLED) {
        // 此时调用then的promise已经完成,可以执行回调
        setTimeout(() => handleFulfilled(this.value));
      } else if (self.status === REJECTED) {
        // 此时调用then的promise已经为拒绝状态,可以执行回调
        setTimeout(() => handleRejected(this.reason));
      }
    });
  }
}

以上就是Promise的简单实现,其实我们也就主要实现了整体的架子和then方法,如果错误也请大家纠正哈。下一篇我们将继续实现resolve, reject, race,all这些方法.