手写Promise源码

265 阅读2分钟

按照Promise/A+ 规范实现代码(promisesaplus.com/) Promise类实现:

const RESOLVED = "RESOLVED";
const REJECTED = "REJECTED";
//因为所有的promise都遵循这个规范 。规定这里写法应该兼容所有promise

const resolvePromise = (promise2, x, resolve, reject) => {
  //判断x 的值 和promise2 是不是同一个 如果是同一个 就不要再等待了 直接出错即可
  if(promise2 === x) {
    return reject(new TypeError('Chaning cycle .....'))
  }
  //判断数据类型 typeof constructor instanceof toString
  if(typeof x === 'object' &&  x !== null || typeof x === 'function' ) {
    let called; // 内部测试的时候 会成功和失败都调用
    try {
      let then = x.then   //取then有可能这个then属性是通过defineProperty来定义的
      if(typeof then === 'function') { //当前有then方法 姑且认为x是promise
        then.call(x, y => {  // 能保证不用再次取then的值
          if(called) {
            return
          }
          called = true //防止多次调用成功和失败
          resolvePromise(promise2, x, resolve, reject)  // 采用promise的成功结果 向下传递
        }, r => {
          if(called) {
            return
          }
          called = true //防止多次调用成功和失败
          reject(r)  // 采用promise的成功结果 向下传递
        }) 
      }
      else {
        resolve(x) // 说明x是一个普通的对象 直接成功即可
      }
    } catch (error) {
      //promise失败了 有可能还能调用成功
      if(called) {
        return
      }
      called = true //防止多次调用成功和失败
      reject(error)
    }
  }
  else {
    // x 是一个普通值
    resolve(x) //直接让promise2成功即可
  }
}

class Promise {
  constructor(executor) {
    //executor 执行器
    this.status = PENDING; //默认等待状态
    this.value = undefined; //成功的值
    this.reason = undefined; // 失败的原因
    this.onResolvedCallbacks = []; //成功的回调的数组
    this.onrejectedCallbacks = []; //失败的回调的数组

    //成功的函数
    const resolve = (value) => {
      if (this.status === PENDING) {
        this.status = RESOLVED;
        this.value = value;
        this.onResolvedCallbacks.forEach((fn) => fn()); //发布
      }
    };

    //失败的原因
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        this.onrejectedCallbacks.forEach((fn) => fn()); // 发布
      }
    };

    try {
      executor(resolve, reject); //执行器立即执行
    } catch (error) {
      reject(error); //如果执行器发生错误 也调用reject
    }
  }
  then(onfulfilled, onrejected) { //then 目前有两个参数
    // onfulfilled onrejected 是可选参数
    onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : val => val
    onrejected = typeof onrejected === 'function' ? onrejected : err => {
      throw err
    }
    let promise2 = new Promise((resolve, reject) => { //executor 会立刻执行
      //同步的时候
      if (this.status === RESOLVED) {
        setTimeout(() => {
          try {
            let x = onfulfilled(this.value);
            // resolve(x)
            // x可能是普通值,也可能是promise
            // 判断x的值 => promise2的状态
            resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0)

      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          let x = onrejected(this.reason);
          // resolve(x)
          // x可能是普通值,也可能是promise
          // 判断x的值 => promise2的状态
          resolvePromise(promise2, x, resolve, reject)
        }, 0)

      }
      //如果是异步就先订阅好
      if (this.status === PENDING) {
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            let x = onfulfilled(this.value);
            // resolve(x)
            // x可能是普通值,也可能是promise
            // 判断x的值 => promise2的状态
            resolvePromise(promise2, x, resolve, reject)
          }, 0)

        });
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            let x = onrejected(this.reason);
            // resolve(x)
            // x可能是普通值,也可能是promise
            // 判断x的值 => promise2的状态
            resolvePromise(promise2, x, resolve, reject)
          }, 0)

        });
      }
    })
    return promise2
  }
}

// --------------------------

Promise.defer = Promise.deferred = function() {
  let dfd = {}
  dfd.promise = new Promise((resolve,reject) => {
    dfd.resolve = resolve
    dfd.reject = reject
  })
  return dfd
}

module.exports = Promise;

欢迎访问小程序:女友睡前故事~