Promise源码阅读之构造函数+then过程

前言

Promise是异步编程的一种方案,ES6规范中将其写入规范标准中,统一了用法。
考虑到浏览器的兼容性,Vue项目中使用promise,就具体阅读promise源码,看看内部的具体实现。

具体分析

通过具体实例来阅读promise源码的实现,实例如下:

new Promise(function (resolve, reject) {
  get('http://www.google.com', function (err, res) {
    if (err) reject(err);
    else resolve(res);
  })
}).then(function(res) {
	// 相关处理
});

Promise库的GitHub地址,实际上在源码中只需要关注下面几个文件即可(这几个文件实现了经常使用的API):

  • core.js
  • es6-extensions.js
  • finally.js

core.js

核心文件,核心功能是:

提供Promise构造函数的定义以及resolve、reject的具体处理

ES6 Promises规范中,Promise代表异步操作,其状态有三个:

pending:进行中
fulfilled:已成功
rejected: 已失败

因为promise中需要关注的代码量不是很多,就结合具体的代码进行。

Promise构造函数

Promise构造函数中的处理:

function Promise(fn) {
  // 防止Promise()作为函数调用
  // 浏览器中作为函数此处this === window,并没有起到要达到的效果
  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');
  }
  // Promise内部维护的状态,默认为0即为pending,进行中
  this._deferredState = 0;
  this._state = 0;
  this._value = null;
  this._deferreds = null;
  if (fn === noop) return;
  doResolve(fn, this);
}
doResolve

在这里插入图片描述
从doResolve函数可知,内部实际上是调用tryCallTwo函数来处理,而tryCallTwo函数的处理实际上就是调用Promise中传递的fn函数,并将resolve和reject的回调函数传递到fn中,源码如下:

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

这里a就是表示处理resolve状态的函数,相对应的b就是处理rejected状态的函数

resolve

从上面逻辑中可知当执行resolve时,内部会调用已定义好的resolve函数来处相关逻辑。
在这里插入图片描述
这里需要的点在getThen函数以及then结果的判断,处理了三个情况:

  • getThen执行错误的处理
  • then是Promise对象的处理
  • then是函数的处理

为什么要这么处理这几种情况,就需要去看getThen具体实现的功能,通过源码可知:

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

通过上面的逻辑处理可知:

resolve这边实际上就是处理newValue,即执行了new Promise后之后传递给resolve的参数问题

主要的判断参数是否存在并且是否是object或function,如果是object或function,则会调用getThen获取then进行下面的判断:

  • then是否等于IS_ERROR,即getThen是否执行出错
  • newValue是否是Promise对象
  • then是否是函数

实际上上面的判断都是处理newValue中是否存在then函数的问题。

只要newValue中不存在then函数,就会设置_state和_value,并调用finale函数。

reject函数

reject中处理逻辑就是设置state和value值,调用finale函数。

state设置为2,表示rejected状态

finale函数

finale函数式实际上是处理fulfilled状态和rejected,分别调用handle来处理相关逻辑。
当你使用new Promise实际上_deferredStat默认为0,而且在之前的处理逻辑中并没有相关处理,因为Promise中是异步操作实际上这边是在then函数中处理。

then函数

Promise.prototype.then = function(onFulfilled, onRejected) {
  // 处理非Promise构造函数创建的情况,例如prototype继承未修改constructor时
  if (this.constructor !== Promise) {
    return safeThen(this, onFulfilled, onRejected);
  }
  var res = new Promise(noop);
  handle(this, new Handler(onFulfilled, onRejected, res));
  return res;
};

从上面可知链式调用的实现以及then函数内部的主要处理是handle函数。
在这里插入图片描述

首先看看Handler构造函数的作用,实际上是then函数内部会构建promise对象的链表结构,Handler的属性:

function Handler(onFulfilled, onRejected, promise){
  // then函数的resolve函数
  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  // then函数的reject函数
  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  // 下一个promise对象,实际上就是then函数返回的
  this.promise = promise;
}

而handle中的处理逻辑主要点如下:

判断上一个Promise中state,根据状态设置_deferredState和_deferreds的值
根据上一个Promise中state不为0,就会执行handleResolved

实际上handle就是判断上一个Promise中的异步操作是否执行了,没有执行就等待。

实际上上一个promise执行了,就会改变_state的值,而then函数根据_state的值来做相应的判断

而在handleResolved函数中实际上会调用resolve或reject重复new Promise中一部分动作,这里就需要通过实例去整体梳理这样好理解些。

根据实例梳理整个过程如下:

  • new Promise(fn)构建promise实例对象,会立即执行fn函数
  • fn函数式get请求,这是一个异步操作,而这个异步操作的处理逻辑中会主动触发resolve或reject,所以new Promise创建的promise会等待主动触发resolve或reject
  • Promise等待,但是这边的同步代码then函数就执行了,调用Promise.prototype.then暴露的API
  • then函数中就构建另一个Promise,创建Hander对象形成链式,并执行handle函数
  • handle函数执行就要判断上一个Promise实例的_state(实例这里是new Promise创建的),因为上一个Promise执行异步操作的,_state为0
  • _state为0,就设置了_deferredState为1,然后等待上一个Promise执行完异步操作

当实例中new Promise中的get请求成功后,就会触发resolve,此时:

  • 会调用resolve函数,resolve函数中则会判断传递进来的数据是否是对象或函数(即处理存在then函数的情况)
  • 如果不存在then函数的情况下,就设置_state以及_value值,并调用finale函数
  • finale函数中就判断_deferredState值,在上一个Promise等待异步操作中then函数就设置了该值为1,则会调用handle函数
  • 实际上调用handle就是去执行handleResolved,执行then函数传递进来的resolve函数,即使用asap来执行resolve函数(如果此时resolve是一个异步操作,实际上就是重复new Promise中主动触发resolve的过程),注意此时是另一个Promise对象了
  • 此时resolve的处理就是将上一个Promise传递进来的value值设置为下一个Promise的value值,并将当前的Promise的state状态置为1
  • 此时会执行finale,实际上这个函数在此时没有执行任何逻辑,因为此时_state为1,即使再接then函数,也不会设置_deferredState了,而是直接执行handleResolved,因为此步实际上是被asap主动执行了

如此反复上面的过程。

以当时实例promise整个逻辑处理如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/s1879046/article/details/83506401
今日推荐