简单 Promise 实现

250 阅读4分钟

1. Promise1.0 版本

简单的发布订阅实现 Promise

存在的问题是:then 方法执行回调函数的时候 value 值不确定

function Promise(fn) {

    // 同步任务执行得到的结果value,作为私有变量存储在Promise中
    var value = undefined;

    // 模拟then方法
    this.then = function(callback) {
      callback(value);
    }

    // 模拟resolve
    function resolve(val) {
      value = val;
    }

    // 执行异步任务
    fn(resolve);
}

2. Promise 2.0 版本

通过加入状态标志位,来百分之百确保回调执行的时候,value 值一定存在

相比第一版,添加了两个私有变量,statuscb

function Promise(fn) {

    // 异步任务执行得到的结果即 value,作为私有变量存储在Promise中
    var value = undefined;

    // 异步任务当前的状态(pending | resolved),作为私有变量存储在Promise
    var status = "pending";

    // 异步任务暂存
    var cb = null;

    // 模拟then方法
    this.then = function(callback) {
      // 1.如果fn执行结束(意味着一个同步任务),直接执行回调即可
      if(status == "resolved") {
        callback(value);
      }
      // 2.如果fn执行还未结束(意味着一个异步任务),暂存callback回调以后执行
      if(status == "pending") {
        cb = callback;
      }
    }

    // 模拟resolve方法
    function resolve(val) {
      pending = "resolved";
      value = val;
      // 1.如果回调函数暂存了,执行回调
      if(cb) {
        cb(value);
      }
      // 2.如果回调函数未暂存,啥也不用做
    }
    fn(resolve);
}

3. Promise 3.0 版本

then 方法,需要返回一个 Promise,这样能链式调用

相比第二版,添加了一个私有变量 nResolve

function Promise(fn) {
  var value = undefined;
  var status = "pending";
  var cb = null;
  var nResolve = null;
  
  this.then = function(callback) {
    return new Promise(function(nextResolve) {
      // 1.如果fn执行结束(意味着一个同步任务),直接执行回调即可
      if(status == "resolved") {   
        let nextValue = callback(value);
        nextResolve(nextValue);
      }     
      // 2.如果fn执行未结束(意味着一个异步任务),暂存callback回调以后执行,暂存nextResolve以后执行
      if(status == "pending") {
        cb = callback;
        nResolve = nextResolve;
      }
    })
  }   
  function resolve(val) {
    status = "resolved";
    value = val;
    // 1.如果回调函数存在了,执行回调和nextReoslve
    if(cb) {
      let nextValue = cb(value);
      nResolve(nextValue);
    }
   // 2.如果回调函数不存在,啥也不用做
  }
  
  fn(resolve);
}

4. Promise 4.0 版本

如果then方法返回的就是一个Promise对象,那么我们得处理一下,获取里面的value

function Promise(fn) {
  var value = undefined;
  var status = "pending";
  var cb = null;
  var nResolve = null;
  
  this.then = function(callback) {
    return new Promise(function(resolve) {
      // 1.如果fn执行结束(意味着一个同步任务),直接执行回调即可
      if(status == "resolved") {
        let nextValue = callback(value);
        nextResolve(nextValue);      
      }    
      // 2.如果fn执行未结束(意味着一个异步任务),暂存callback回调以后执行,暂存nextResolve以后执行
      if(status == "pending") {
        cb = callback;
        nResolve = nextResolve;      
      }
   });
  }  
  function resolve(val) {
    // 判断下,这个val是否是个Promise
    if(val && typeof val.then == "function") {
      val.then(resolve);
    }

    status = "resolved";
    value = val;
    // 1.如果回调函数存在了,执行回调和nextReoslve
    if(cb) {
      let nextValue = cb(value);
      nResolve(nextValue);
    }
    // 2.如果回调函数不存在,啥也不用做
  }

  fn(resolve);
}

5. Promise 5.0 版本

很简单,只要把 reject 加入即可,思路和 resolve 类似

function Promise(fn) {
  var value = undefined;
  var status = "pending";
  var cb = null;
  var nResolve = null;
  var nReject = null;
  
  this.then = function(callback) {
    return new Promise(nextResolve, nextReject) {
      // 1.如果fn执行结束(意味着一个同步任务),直接执行回调即可
      if(status == "resolved") {
        let nextValue = callback(value);
        nextResolve(nextValue);      
      }
      if(status == "rejected") {
        let nextError = callback(value);
        nextReject(nextError);
      }
      // 2.如果fn执行未结束(意味着一个异步任务),暂存callback回调以后执行,暂存nextResolve以后执行
      if(status == "pending") {
        cb = callback;
        nResolve = nextResolve;      
      }
    }
  }
  
  function resolve(val) {
    // 判断下,这个val是否是个Promise
    if(val && typeof val.then == "function") {
      val.then(resolve);
    }

    status = "resolved";
    value = val;
    // 1.如果回调函数存在了,执行回调和nextReoslve
    if(cb) {
      let nextValue = cb(value);
      nResolve(nextValue);
    }
   // 2.如果回调函数不存在,啥也不用做
  }
  function reject(val) {
   // 判断下,这个val是不是Promise
   if(val && typeof val.then == "function") {
     val.then(reject);
   }
   
   status = "rejected";
   value = val;
  
   // 1.如果回调函数存在,执行回调和nextReject
   if(cb) {
     let nextError = cb(value);
     nReject(nextError);
   }
   // 2.如果回调函数不存在,啥也不用做
  }

  fn(resolve, reject);
}

6. 添加try catch

存在的问题:resolve, then 方法里面的异常无法捕获,需要 try catch 交给 下个promise 来处理

所以 then().catch() 这种写法,可以保证捕获内部的错误

function Promise(fn) {
  var value = undefined;
  var status = "pending";
  var cb = null;
  var nResolve = null;
  var nReject = null;
  
  this.then = function(callback) {
    return new Promise(nextResolve, nextReject) {
      let nextValue = undefined,
          nextError = undefined;
      // 1.如果fn执行结束(意味着一个同步任务),直接执行回调即可
      if(status == "resolved") {
        try {
          nextValue = callback(value);
        }
        catch(e) {
          nextReject(e);
        }
        nextResolve(nextValue);      
      }
      if(status == "rejected") {
        try {
          nextError = callback(value);
        }
        catch(e) {
          nextReject(e);
        }
        nextReject(nextError);
      }
      // 2.如果fn执行未结束(意味着一个异步任务),暂存callback回调以后执行,暂存nextResolve以后执行
      if(status == "pending") {
        cb = callback;
        nResolve = nextResolve;      
      }
    }
  }
  
  function resolve(val) {
    // 判断下,这个val是否是个Promise
    if(val && typeof val.then == "function") {
      val.then(resolve);
    }

    status = "resolved";
    value = val;
    // 1.如果回调函数存在了,执行回调和nextReoslve
    let nextValue = undefined;
    if(cb) {
      try {
        nextValue = cb(value);
      }
      catch(e) {
        nReject(e);
      }
      nResolve(nextValue);
    }
   // 2.如果回调函数不存在,啥也不用做
  }
  function reject(val) {
   // 判断下,这个val是不是Promise
   if(val && typeof val.then == "function") {
     val.then(reject);
   }
   
   status = "rejected";
   value = val;
  
   // 1.如果回调函数存在,执行回调和nextReject
   if(cb) {
     let nextError = cb(value);
     nReject(nextError);
   }
   // 2.如果回调函数不存在,啥也不用做
  }

  fn(resolve, reject);
}

7. 静态方法all,race等实现