xiaoxiaosaohuo/Note

Promise/A+源码分析

Opened this issue · 0 comments

Promise/A+源码分析

Promise相当于一个状态机,有三种状态

  • pending
  • fulfilled
  • rejected

promise 对象初始化状态为 pending 2.当调用resolve(成功),会由pending => fulfilled 3.当调用reject(失败),会由pending => rejected

Promise/A+中也是这样实现的,但是多一个state。

  • 0 - pending
  • 1 - fulfilled with _value
  • 2 - rejected with _value
  • 3 - 当resolve一个promise的时候,state被置为3,一般是调用then方法之前该promise已经被resolve,且resolve的是一个promise时会发生

简单的工具方法

这几个方法主要是为了封装try-catch

var LAST_ERROR = null;
var IS_ERROR = {};
function getThen(obj) {
  try {
    return obj.then;
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

function tryCallOne(fn, a) {
  try {
    return fn(a);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

Promise 构造函数

function Promise(fn) {
  if (typeof this !== 'object') {
    throw new TypeError('Promises must be constructed via new');
  }
  if (typeof fn !== 'function') {
    throw new TypeError('Promise constructor\'s argument is not a function');
  }
  this._deferredState = 0;
  this._state = 0;
  this._value = null;
  this._deferreds = null;
  if (fn === noop) return;
  doResolve(fn, this);
}

属性解释

  • _deferredState 延迟状态,0表示没有需要延迟处理的任务,1表示有一个任务,2表示有多个任务
  • _state 见上面的关于状态转换的解释
  • _deferreds延迟处理的任务队列,_deferredState为1时是一个对象,_deferredState为2时是一个数组

实例化Promise时需要执行回调函数fn,也就是执行器。

例如:

var promise1 = new Promise(function(resolve, reject) {
   setTimeout(()=>{
        resolve(1);
   },500)
  });

fn 将在doResolve方法中执行

doResolve

function doResolve(fn, promise) {
  var done = false;
  var res = tryCallTwo(fn, function (value) {
    if (done) return;
    done = true;
    resolve(promise, value);
  }, function (reason) {
    if (done) return;
    done = true;
    reject(promise, reason);
  });
  if (!done && res === IS_ERROR) {
    done = true;
    reject(promise, LAST_ERROR);
  }
}

doResolve 方法功能

  • 保证onFulfilled和 onRejected 只被调用一次,done变量做开关来控制
  • 向Promise构造器的fn注入resovle和reject匿名函数
  • 捕获执行器fn执行中的错误,有错的话直接reject

可以看到当在Promise实例化时调用resolve或者reject方法,最终会调用Promise中的resolve和reject方法并传入当前的promise实例

resolve

function resolve(self, newValue) {
  if (newValue === self) {
    return reject(
      self,
      new TypeError('A promise cannot be resolved with itself.')
    );
  }
  if (
    newValue &&
    (typeof newValue === 'object' || typeof newValue === 'function')
  ) {
    var then = getThen(newValue);
    if (then === IS_ERROR) {
      return reject(self, LAST_ERROR);
    }
    if (
      then === self.then &&
      newValue instanceof Promise
    ) {
      self._state = 3;
      self._value = newValue;
      finale(self);
      return;
    } else if (typeof then === 'function') {
      doResolve(then.bind(newValue), self);
      return;
    }
  }
  self._state = 1;
  self._value = newValue;
  finale(self);
}

resolve处理逻辑

  • 判断是否是循环引用
  • 判断newValue是否是对象或者函数
    • 有then方法就取出then方法
    • 如果newValue是个promise,将state置为3,value置为newValue,调用finale处理,然后返回
    • 如果then是一个函数且有不是promise,继续调用doResolve处理
  • 将state置为1,value置为newValue,调用finale处理

reject

function reject(self, newValue) {
  self._state = 2;
  self._value = newValue;
  if (Promise._onReject) {
    Promise._onReject(self, newValue);
  }
  finale(self);
}
  • 将state置为2
  • 调用finale处理

finale

function finale(self) {
  if (self._deferredState === 1) {
    handle(self, self._deferreds);
    self._deferreds = null;
  }
  if (self._deferredState === 2) {
    for (var i = 0; i < self._deferreds.length; i++) {
      handle(self, self._deferreds[i]);
    }
    self._deferreds = null;
  }
}

判断当前的promise的_deferredState,调用handle处理延迟队列,然后将该promise的_deferreds清空

handle

处理延迟任务

function handle(self, deferred) {
  while (self._state === 3) {
    self = self._value;
  }
  if (Promise._onHandle) {
    Promise._onHandle(self);
  }
  if (self._state === 0) {
    if (self._deferredState === 0) {
      self._deferredState = 1;
      self._deferreds = deferred;
      return;
    }
    if (self._deferredState === 1) {
      self._deferredState = 2;
      self._deferreds = [self._deferreds, deferred];
      return;
    }
    self._deferreds.push(deferred);
    return;
  }
  handleResolved(self, deferred);
}

判断当前的promise状态进行不同的处理

  • 如果为3,直接将当前的promise替换为新的promise self = self._value
  • 如果为0,表明是pending,修改promise对延迟任务状态deferredState,更新延迟任务队列_deferreds

最后将延迟任务调用handleResolved进行异步调度,即放入微任务队列。

deferred是什么?

Promise原型上有then方法,该方法会返回一个promise。这个deferred是一个持有该promise的对象

Promise.prototype.then = function(onFulfilled, onRejected) {
  if (this.constructor !== Promise) {
    return safeThen(this, onFulfilled, onRejected);
  }
  var res = new Promise(noop);
  handle(this, new Handler(onFulfilled, onRejected, res));
  return res;
};

function Handler(onFulfilled, onRejected, promise){
  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  this.promise = promise;
}

可以看到then方法实例化一个Promise,并且实例化了一个Handler

Handler结构

  • onFulfilled 不存在就为null
  • onRejected
  • promise

handleResolved

function handleResolved(self, deferred) {
  asap(function() {
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {
      if (self._state === 1) {
        resolve(deferred.promise, self._value);
      } else {
        reject(deferred.promise, self._value);
      }
      return;
    }
    var ret = tryCallOne(cb, self._value);
    if (ret === IS_ERROR) {
      reject(deferred.promise, LAST_ERROR);
    } else {
      resolve(deferred.promise, ret);
    }
  });
}

调用asap方法将任务加入微任务队列,Asap原理分析

当微任务队列的任务执行时,会判断该promise的状态决定调用resolve还是reject方法。在调用then方法时我们可能不会每次都传入两个回调函数,所以这里进行了判断处理

  • 如果没有回调函数,调用promise的resolve或者reject方法处理,然后返回。

  • 如果存在回调方法,调用你tryCallOne执行回调,且传入promise返回的value,所以我们的回调中可以接收到promise的返回值(包括reject的error),执行完毕之后根据我们自定义回调函数的返回值继续调用resolve或者reject 。

从这里可以看出,上游一个promise的会影响延迟任务的promise的状态,因为resolve和reject都会修改promise的状态

Promise.resolve

var TRUE = valuePromise(true);
var FALSE = valuePromise(false);
var NULL = valuePromise(null);
var UNDEFINED = valuePromise(undefined);
var ZERO = valuePromise(0);
var EMPTYSTRING = valuePromise('');

function valuePromise(value) {
  var p = new Promise(Promise._noop);
  p._state = 1;
  p._value = value;
  return p;
}

Promise.resolve = function (value) {
  if (value instanceof Promise) return value;

  if (value === null) return NULL;
  if (value === undefined) return UNDEFINED;
  if (value === true) return TRUE;
  if (value === false) return FALSE;
  if (value === 0) return ZERO;
  if (value === '') return EMPTYSTRING;

  if (typeof value === 'object' || typeof value === 'function') {
    try {
      var then = value.then;
      if (typeof then === 'function') {
        return new Promise(then.bind(value));
      }
    } catch (ex) {
      return new Promise(function (resolve, reject) {
        reject(ex);
      });
    }
  }
  return valuePromise(value);
};

valuePromise方法将非promise值转化为一个promise,返回一个fulfilled状态的promise实例

Promise.resolve 主要是用valuePromise将一个非promise值转化为一个promise,同时还处理了value是对象或者是函数的情况

Promise.reject


Promise.reject = function (value) {
  return new Promise(function (resolve, reject) {
    reject(value);
  });
};

返回一个被reject的promise实例

Promise.prototype.catch

Promise.prototype['catch'] = function (onRejected) {
  return this.then(null, onRejected);
};

Promise.race

Promise.race = function (values) {
  return new Promise(function (resolve, reject) {
    values.forEach(function(value){
      Promise.resolve(value).then(resolve, reject);
    });
  });
};

这里利用了一个promise只能被resolve一次的特性

Promise.all

Promise.all = function (arr) {
  var args = Array.prototype.slice.call(arr);

  return new Promise(function (resolve, reject) {
    if (args.length === 0) return resolve([]);
    var remaining = args.length;
    function res(i, val) {
      if (val && (typeof val === 'object' || typeof val === 'function')) {
        if (val instanceof Promise && val.then === Promise.prototype.then) {
          while (val._state === 3) {
            val = val._value;
          }
          if (val._state === 1) return res(i, val._value);
          if (val._state === 2) reject(val._value);
          val.then(function (val) {
            res(i, val);
          }, reject);
          return;
        } else {
          var then = val.then;
          if (typeof then === 'function') {
            var p = new Promise(then.bind(val));
            p.then(function (val) {
              res(i, val);
            }, reject);
            return;
          }
        }
      }
      args[i] = val;
      if (--remaining === 0) {
        resolve(args);
      }
    }
    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });
};
  • 将传入的数组浅复制,返回一个Promise
  • 使用for循环执行数组中的promise
  • 每执行完一个promise将其返回结果存入args中
  • 当全部执行完毕之后调用resolve修改promise的状态
  • 当某一个promise被reject时调用最外层的reject方法将整个promise拒绝掉

Promise.prototype.finally

Promise.prototype.finally = function (f) {
  return this.then(function (value) {
    return Promise.resolve(f()).then(function () {
      return value;
    });
  }, function (err) {
    return Promise.resolve(f()).then(function () {
      throw err;
    });
  });
};

finally() 方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数

finally() 虽然与 .then(onFinally, onFinally) 类似,它们不同的是:

  • 由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
  • 与Promise.resolve(2).then(() => {}, () => {}) (resolved的结果为undefined)不同,Promise.resolve(2).finally(() => {}) resolved的结果为 2。
  • 同样,Promise.reject(3).then(() => {}, () => {}) (resolved 的结果为undefined), Promise.reject(3).finally(() => {}) rejected 的结果为 3。