Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I_9 #9

Open
noopn opened this issue Aug 20, 2018 · 0 comments
Open

I_9 #9

noopn opened this issue Aug 20, 2018 · 0 comments

Comments

@noopn
Copy link
Owner

noopn commented Aug 20, 2018

Promise实现原理

一个 Promise 就是一个代表了异步操作最终完成或者失败的对象。
promise本质上是一个绑定了回调的对象,而不是将回调传进函数内部。

通过在浏览器中打印Promise对象查看其结构
Promise
Promise 流程示意图
promise

promise-polyfill的为例,来分析一下Promise的实现

function Promise(fn) {
  //构造函数 new Promise(function(){})
  if (!(this instanceof Promise))
  //如果没有通过构造函数调用报错
    throw new TypeError('Promises must be constructed via new');
  //构造函数参数不是函数 报错
  if (typeof fn !== 'function') throw new TypeError('not a function');
  /** @type {!number} */
  //0 表示 pending: 初始状态,既不是成功,也不是失败状态。
  //1 表示 fulfilled: 意味着操作成功完成。
  //2 表示 rejected: 意味着操作失败
  this._state = 0;
  /** @type {!boolean} */
  this._handled = false;
  /** @type {Promise|undefined} */
  // value 表示异步操作的返回值
  this._value = undefined;
  /** @type {!Array<!Function>} */
  // deferreds 表示回调的事件队列
  this._deferreds = [];
  doResolve(fn, this);
}

doResolve

function doResolve(fn, self) {
  //fn 为new Promise(fn) 参数
  var done = false;
  try {
    fn(
      function (value) {
        if (done) return;
        done = true;
        resolve(self, value);  //通过主动调用返回一个Promise 对象
      },
      function (reason) {
        if (done) return;
        done = true;
        reject(self, reason);
      }
    );
  } catch (ex) {
    if (done) return;
    done = true;
    reject(self, ex);
  }
}

resolve

function resolve(self, newValue) {
  //self 创建的promise 对象 ,value 异步或同步的返回值
  try {
    // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
    //resolve 传参的几种情况
    //1. 传入创建出来的Promise 对象,原生会报Promise对象不能链式传递的错误
    //2. 传入带有then方法的对象对象或者函数
    //3. 传入另一个Promise对象会直接返回传入对象
    //4. 其他基本类型值或者引用类型值
    if (newValue === self)
      throw new TypeError('A promise cannot be resolved with itself.');
    if (
      newValue &&
      (typeof newValue === 'object' || typeof newValue === 'function')
    ) {
      var then = newValue.then;
      //如果返回的是一个Promise对象
      if (newValue instanceof Promise) {
        self._state = 3;
        self._value = newValue;//self 为回调队列中,下个未绑定值的Promise
        finale(self);
        return;
      } else if (typeof then === 'function') {
        doResolve(bind(then, newValue), self);
        return;
      }
    }
    //其他情况,Promise对象状态变1,表示已完成
    self._state = 1;
    //保存同步或异步操作的返回值
    self._value = newValue;
    
    finale(self);
  } catch (e) {
    reject(self, e);
  }
}

finale

//finale 表示最终的意思,在有resolve的结果后就可以执行then方法中的回调,
//then方法同样调用下面的handle方法,讲回调函数放入_deferreds事件队列中,在稍后介绍then方法 
function finale(self) {
 //promise 状态为错误且回调队列中没有事件
  if (self._state === 2 && self._deferreds.length === 0) {
    Promise._immediateFn(function () {
      if (!self._handled) {
        Promise._unhandledRejectionFn(self._value);
      }
    });
  }
  //如果回调队列中有事件则通过handle函数循环释放,也就是原生中的微任务队列
  for (var i = 0, len = self._deferreds.length; i < len; i++) {
    handle(self, self._deferreds[i]);
  }
  //全部执行后清空事件队列
  self._deferreds = null;
}

handle

//handle 用来执行事件队列中的回调函数,也就是then添加进去的方法
//handle 方法把添加事件和释放事件一起在handle中处理
//所以finale 中执行事件队列中的方法会调用handle,then中添加事件到队列中也是调用handle方法
function handle(self, deferred) {
  //如果返回值为Promsie对象,当前Promise赋值为返回的Promise对象
  while (self._state === 3) {
    self = self._value;
  }
  //状态为0初始状态时,把事件加入队列中.如果返回值为Promsie对象,在上一步复制后也会走到这里,实现的是原生Promise在函数里面,和外面都可以使用then的功能,把后面的回调添加到新的Promise回调里面,也就是为什么需要循环释放promise队列哪怕他每次只添加了一个。
  if (self._state === 0) {
    self._deferreds.push(deferred);
    return;
  }
  self._handled = true;
  // _immediateFn 是一个异步函数,类似于settimeout,在最后统一介绍其他函数的作用
  //为什么在拿到值以后还要异步执行?
  Promise._immediateFn(function () {
   //Promise 状态为1已完成 ,使用事件中onFulfilled 
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
  
    if (cb === null) {
      (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
      return;
    }
    var ret;
    try {
      //执行回调函数,传入异步或同步的返回值
      ret = cb(self._value);
    } catch (e) {
      reject(deferred.promise, e);
      return;
    }
    //
    resolve(deferred.promise, ret);
  });
}

then

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

一个可能有疑问的地方,为什么在finale中以为循环施法了then,方法添加的回调队列,当时在handle中执行完回调后还要,继续执行resolve,那不就所有的回调方法都执行了两次。

需要注意的是then方法每次返回一个新的Promise对象,而每个then方法添加的回调函数,都是绑定在在不同Promise对象上放入回调队列中的。保证回调队列的按顺序执行,在每一个回调执行后在执行下个回调,可控的拿到上一个回调的返回值

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant