当前位置: 移动技术网 > IT编程>网页制作>CSS > Promise源码分析

Promise源码分析

2019年01月02日  | 移动技术网IT编程  | 我要评论

前言

then/promise项目是基于promises/a+标准实现的promise库,从这个项目当中,我们来看promise的原理是什么,它是如何做到的,从而更加熟悉promise

分析

从index.js当中知道,它是先引出了./core.js,随后各自执行了其他文件的代码,通过requeire的方法。

我们首先先想一下最基础的promise用法

new promise((resolve, reject) =>  {
    resolve(4);

}).then(res => {
    console.log(res); // export 4
});

promise中的标准

标准中规定:

promise对象初始状态为 pending,在被 resolve 或 reject 时,状态变为 fulfilled 或 rejected resolve接收成功的数据,reject接收失败或错误的数据 promise对象必须有一个 then 方法,且只接受两个可函数参数 onfulfilled、onrejected

index.js

'use strict';

module.exports = require('./core.js');
require('./done.js');
require('./finally.js');
require('./es6-extensions.js');
require('./node-extensions.js');
require('./synchronous.js');

我们先看src/core.js

function promise(fn) {
  // 判断 this一定得是object不然就会报错,这个方法一定得要new出来
  if (typeof this !== 'object') {
    throw new typeerror('promises must be constructed via new');
  }
  // 判断fn 一定得是一个函数
  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很关键
  doresolve(fn, this);
}

promise是一个构造方法,开始时,它进行了校验,确保了fn是一个函数,随后对一些变量进行了初始化,最后执行了doresolve()

我们接着看doresolve这个方法。

/**
 * take a potentially misbehaving resolver function and make sure
 * onfulfilled and onrejected are only called once.
 *
 * makes no guarantees about asynchrony.
 */
// 
// 确保`onfulfilled`和`onrejected`方法只调用一次
// 不保证异步
function doresolve(fn, promise) {
  var done = false;
  var res = trycalltwo(fn, function (value) {
    // 如果done 为true 则return
    if (done) return;
    done = true;
    // 回调执行 resolve()
    resolve(promise, value);
  }, function (reason) {
    // 如果done 为true 则return
    if (done) return;
    done = true;
    reject(promise, reason);
  });
  // res为trucalltwo()的返回值
  // 如果done没有完成 并且 res 是 `is_error`的情况下
  // 也会执行reject(),同时让done完成
  if (!done && res === is_error) {
    done = true;
    reject(promise, last_error);
  }
}

doresolve最关键的是执行了trycalltwo方法,这个方法的第二,第三个参数都是回调,当执行回调后,done为true,同时各自会执行resolve()或者reject()方法。最后当trycalltwo的返回值为is_error时,也会执行reject()方法。

我们先来看一下trycalltwo方法

function trycalltwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    last_error = ex;
    return is_error;
  }
}

fn实际就是promise初始化时的匿名函数(resolve, reject) => {},a,b则代表的是resolve()和reject()方法,当我们正常执行完promise函数时,则执行的是resolve则在doresolve中,我们当时执行的第二个参数被回调,如果报错,reject()被执行,则第二个参数被回调。最后捕获了异常,当发生了报错时,会return is_error,非报错时会return undinfed

再回到刚才的doresolve方法,当执行了第二个参数的回调之后,会执行resolve方法

function resolve(self, newvalue) {
  // promise resolution procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
  // 不能吃传递自己
  if (newvalue === self) {
    // 报错
    return reject(
      self,
      new typeerror('a promise cannot be resolved with itself.')
    );
  }
  // promise作为参数
  if (
    newvalue &&
    (typeof newvalue === 'object' || typeof newvalue === 'function')
  ) {
    // 获取它的promise方法 读取newvalue.then
    var then = getthen(newvalue);
    if (then === is_error) {
      // 如果then is_error
      return reject(self, last_error);
    }
    if (
      // 如果then是self的then
      // 并且promise
      then === self.then &&
      // newvalue 属于promise
      newvalue instanceof promise
    ) {
      // _state为3
      // 一般then之后走这里
      // 执行then(newvalue)返回了promise
      self._state = 3;
      // selft.value为newvalue
      self._value = newvalue;
      // 当state为3时执行 finale
      finale(self);
      return;
    } else if (typeof then === 'function') {
      doresolve(then.bind(newvalue), self);
      return;
    }
  }
  self._state = 1;
  self._value = newvalue;
  finale(self);
}

在没有链式调用then的情况下(也就是只要一个then)的情况下,会将内部状态_state设置成3,将传入值赋给内部变量_value最后会执行final()方法,不然则会使用doresolve来调用then

我们再来看下reject

function reject(self, newvalue) {
  // _state = 2为reject
  self._state = 2;
  self._value = newvalue;
  if (promise._onreject) {
    promise._onreject(self, newvalue);
  }
  finale(self);
}

在reject当中我们的_state变更为了2,同样最后finale被调用。

我们来看下finale函数

// 执行自己的deferreds
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
      handle(self, self._deferreds[i]);
    }
    // 将deferred 置空
    self._deferreds = null;
  }
}

在该方法当中根据不同的_deferredstate,会执行不同的handle方法。

我们再来看handle方法

function handle(self, deferred) {
  while (self._state === 3) {
    self = self._value;
  }
  // 如果有onhandle方法 则执行该方法
  if (promise._onhandle) {
    promise._onhandle(self);
  }
  // (初始 _state 为0)
  if (self._state === 0) {
    // (初始 _deferredstate 为0)
    if (self._deferredstate === 0) {
      self._deferredstate = 1;
      self._deferreds = deferred;
      return;
    }
    // 如果 _deferredstate是1 则__deferreds是一个数组
    if (self._deferredstate === 1) {
      self._deferredstate = 2;
      self._deferreds = [self._deferreds, deferred];
      return;
    }
    // 当走到这里 _deferredstate应该是2 将deferred
    // 插入到数组当中
    self._deferreds.push(deferred);
    return;
  }
  handleresolved(self, deferred);
}

这里比较关键的应该就是通过deferredstate不同的状态,将deferred放入deferreds当中。另外当我们的_state不为0时,最终会执行handleresolved。

继续看handleresolve()方法

function handleresolved(self, deferred) {
  asap(function() {
    // _state为1时,cb = onfulfilled 否则 cb = onrejected
    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);
    }
  });
}.then((res) => {
}).catch((error) => {
})

在这个方法当中,会根据我们任务(_state)的不同状态,来执行onfulfilled或者onrejected方法。当此方法调用时,也就是我们一个简单的promise的结束。

回到刚才说的promise构造方法结束的时候

设置了promise函数的一些变量

promise._onhandle = null;
promise._onreject = null;
promise._noop = noop;

随后在promise的原型上设置了then方法。

promise.prototype.then = function(onfulfilled, onrejected) {
  // 首先看这是谁构造的 如果不是promise
  // 则return 执行safethen
  if (this.constructor !== promise) {
    return safethen(this, onfulfilled, onrejected);
  }
  // 如果是则初始化一个promise 但是参数 noop 为空对象 {}
  var res = new promise(noop);
  // 随后执行handle方法
  handle(this, new handler(onfulfilled, onrejected, res));
  return res;
};

在then这个方法中首先判断了它是否由promise构造的,如果不是,则返回并执行safethen,不然则执行promise构造一个res对象,然后执行handle方法,最后将promise变量res返回。handle方法之前有提过,在这里,当初始化时_state和_deferred的转改都为0,因此它会将defrred保存到promise当中。

先看一下上面说的safethen方法

function safethen(self, onfulfilled, onrejected) {
  return new self.constructor(function (resolve, reject) {
    var res = new promise(noop);
    res.then(resolve, reject);
    handle(self, new handler(onfulfilled, onrejected, res));
  });
}

流程

需要有一个promise的构造方法,这个构造方法最终会执行它的参数(resolve, reject) => {},声明的then方法会通过handle()方法将onfulfilled和onrejected方法保存起来。当在外部调用resolve或者onrejected时,最终也会执行handle但是它,会最后根据状态来执行onfulfilled或者onrejected。从而到我们的then回调中。

promise的扩展

done

对done的扩展在src/done.js当中

'use strict';

var promise = require('./core.js');

module.exports = promise;
promise.prototype.done = function (onfulfilled, onrejected) {
  var self = arguments.length  this.then.apply(this, arguments) : this;
  self.then(null, function (err) {
    settimeout(function () {
      throw err;
    }, 0);
  });
};

内部执行了then()

finally

对finally的扩展在src/finally.js当中

在promise的标准当中,本身是没有finally方法的,但是在es2018的标准里有,finally的实现如下

'use strict';

var promise = require('./core.js');

module.exports = promise;
promise.prototype.finally = function (callback) {
  return this.then(function (value) {
    return promise.resolve(callback()).then(function () {
      return value;
    });
  }, function (err) {
    return promise.resolve(callback()).then(function () {
      throw err;
    });
  });
};

promise的onfulfilled和onrejected 不管回调的哪个,最终都会触发callback 回调。还要注意的一点是finally的返回也是一个promise。

es6-extensions.js

在es6-extensions.js文件当中包含了es6的一些扩展。

promise.resolve

function valuepromise(value) {
  var p = new promise(promise._noop);
  // 将_state赋值为 非0
  // _value进行保存
  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;

  // value return new promise
  if (typeof value === 'object' || typeof value === 'function') {
    try {
      var then = value.then;
      if (typeof then === 'function') {
        // 返回 返回了一个新的promise对象
        return new promise(then.bind(value));
      }
    } catch (ex) {
        // 如果报错 则返回一个就只
      return new promise(function (resolve, reject) {
        reject(ex);
      });
    }
  }

  return valuepromise(value);
};

promise.reject

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

promise.all

promise.all = function (arr) {
  // 类似深拷贝了一份给了args
  var args = array.prototype.slice.call(arr);

  return new promise(function (resolve, reject) {
    // 判断了all的promise数量
    if (args.length === 0) return resolve([]);
    // remaining则是promise数组的长度
    var remaining = args.length;
    // i为index val 为 promise
    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._state 为 0时 走这里
          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;
      // 当所有的promise执行完 则是remaining为0
      // 则执行resolve();
      if (--remaining === 0) {
        resolve(args);
      }
    }
    // 遍历所有的promise
    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });
};

promise.all()返回的也是一个promise函数。
内部有一个remaining变量每当执行完一个promise函数后就会减一,当所有promise执行完,会执行自己的resolve。

promise.race

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

遍历传入的promise数组,经过promise.resolve(value)的可以看到,如果value是一个promise则户直接将这个value返回,最后数组中的promise哪个优先回调即执行。

promise.property.catch

catch在标准当中也是没有,虽然我们用的比较多

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

catch的回调实际是then(null, onrejected)的回调。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网