博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Promise 源码分析
阅读量:7009 次
发布时间:2019-06-28

本文共 10816 字,大约阅读时间需要 36 分钟。

前言

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中的标准

标准中规定:

  1. Promise对象初始状态为 Pending,在被 resolvereject 时,状态变为 FulfilledRejected
  2. resolve接收成功的数据,reject接收失败或错误的数据
  3. Promise对象必须有一个 then 方法,且只接受两个可函数参数 onFulfilledonRejected

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) => {}ab则代表的是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函数

// 执行自己的deferredsfunction 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()方法将onFulfilledonRejected方法保存起来。当在外部调用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;    });  });};

PromiseonFulfilledonRejected 不管回调的哪个,最终都会触发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)的回调。

广而告之

本文发布于,欢迎Watch & Star ★,转载请注明出处。

欢迎讨论,点个赞再走吧 。◕‿◕。 ~

你可能感兴趣的文章