传送门:

  • axios源码简析(一)——axios入口文件
  • axios源码简析(二)——Axios类与拦截器
  • axios源码简析(三)——请求与取消请求

请求过程

Axios.prototype.request中我们看到,要先通过请求拦截器,才能进行请求。下面看一下dispatchRequest()是如何实现的

// /lib/core/dispatchRequest.jsmodule.exports = function dispatchRequest(config) {// 判断是否已经取消请求throwIfCancellationRequested(config);/* 对请求的url、headers、data进行处理 */// 发动请求的函数,返回一个promisevar adapter = config.adapter || defaults.adapter;return adapter(config).then(function onAdapterResolution(response) {// 判断是否已经取消请求throwIfCancellationRequested(config);// 处理返回的数据response.data = transformData(response.data,response.headers,config.transformResponse);return response;}, function onAdapterRejection(reason) {if (!isCancel(reason)) {// 判断是否已经取消请求throwIfCancellationRequested(config);// 处理返回的错误信息if (reason && reason.response) {reason.response.data = transformData(reason.response.data,reason.response.headers,config.transformResponse);}}return Promise.reject(reason);});

如果用户有在配置中传入adapter,将使用defaults.adapter,根据运行环境是浏览器还是nodejs采取不同的请求方式。

// /lib/defaults.js
function getDefaultAdapter() {var adapter;if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {// nodejs环境adapter = require('./adapters/http');} else if (typeof XMLHttpRequest !== 'undefined') {// 浏览器环境adapter = require('./adapters/xhr');}return adapter;
}var defaults = {adapter: getDefaultAdapter(),/* 其他配置 */
};modules.exports = defaults;

/lib/adapters/http.js/lib/adapters/xhr.js两个文件导出的函数都返回一个promise,具体的实现方式就不分析了。里面有很多http请求的细节,可以仔细研究。

取消请求

官方文档中的调用方法

const CancelToken = axios.CancelToken;
const source = CancelToken.source();axios.get('/user/12345', {cancelToken: source.token
}).catch(function(thrown) {if (axios.isCancel(thrown)) {console.log('Request canceled', thrown.message);} else {// handle error}
});axios.post('/user/12345', {name: 'new name'
}, {cancelToken: source.token
})// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');

我们进入CancelToken类,找到了CancelToken.source()方法:

// /lib/cancel/CancelTokenCancelToken.source = function source() {var cancel;var token = new CancelToken(function executor(c) {cancel = c;});return {token: token,cancel: cancel};
};

可以看出,CancelToken.source().token是一个CancelToken类的实例,CancelToken.source().cancelnew CacelToken()时传入参数(一个函数)的参数(也是个函数),通过CancelToken的构造函数可以看出:

// /lib/cancel/CancelTokenfunction CancelToken(executor) {if (typeof executor !== 'function') {throw new TypeError('executor must be a function.');}var resolvePromise;this.promise = new Promise(function promiseExecutor(resolve) {resolvePromise = resolve;});var token = this;executor(function cancel(message) {if (token.reason) {// Cancellation has already been requestedreturn;}token.reason = new Cancel(message);resolvePromise(token.reason);});
}

CancelToken.source().cancel就是这个函数:

function cancel(message) {if (token.reason) {// Cancellation has already been requestedreturn;}token.reason = new Cancel(message);resolvePromise(token.reason);
}

CancelToken.source().tokenpromisereason两个属性,promise 一直处于 pending状态,reason属性是一个Cancel类的实例,Cancel类的构造函数如下:

// /lib/cancel/Cancel.js
function Cancel(message) {this.message = message;
}Cancel.prototype.toString = function toString() {return 'Cancel' + (this.message ? ': ' + this.message : '');
};Cancel.prototype.__CANCEL__ = true;

在源码中,有以下几种方式检测是否执行了取消请求。
1 检测config.cancelToken是否有reason属性,如果有,将reason抛出,axios进入rejected状态。

// /lib/core/dispatchRequest.js
function throwIfCancellationRequested(config) {if (config.cancelToken) {config.cancelToken.throwIfRequested();}
}module.exports = function dispatchRequest(config) {// 判断是否已经取消请求throwIfCancellationRequested(config);/* ... */
};// /lib/cancel/CancelToken
CancelToken.prototype.throwIfRequested = function throwIfRequested() {if (this.reason) {throw this.reason;}
};

2 在请求过程中,执行CancelToken.source().tokenpromise属性中的resolve函数,参数是CancelToken.source().token.reason,并将其抛出,promise进入rejected状态

if (config.cancelToken) {// Handle cancellationconfig.cancelToken.promise.then(function onCanceled(cancel) {if (!request) {return;}// 取消请求request.abort();// promise进入rejectedreject(cancel);// Clean up requestrequest = null;});
}

调用方法中catch接到的thrown,就是CancelToken.source().token.reason

如果在使用axios时候,只在config中添加{cancelToken: source.token},而不调用source.cancel(),则CancelToken.source().token不会有reason属性,CancelToken.source().token.promise也一直是pending状态。请求不会取消。

参考

深入浅出 axios 源码
axios源码分析——取消请求

(Ajax)axios源码简析(三)——请求与取消请求相关推荐

  1. [tomcat]源码简析 异步/非阻塞和请求构成

    提出疑惑 SpringFramework5.0又新增加了一个功能Webflux(响应式编程),是一个典型非阻塞异步的框架. 我们知道servlet3.0实现异步(AsyncContext),servl ...

  2. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  3. django源码简析——后台程序入口

    django源码简析--后台程序入口 这一年一直在用云笔记,平时记录一些tips或者问题很方便,所以也就不再用博客进行记录,还是想把最近学习到的一些东西和大家作以分享,也能够对自己做一个总结.工作中主 ...

  4. java ArrayList 概述 与源码简析

    ArrayList 概述 与源码简析 1 ArrayList 创建 ArrayList<String> list = new ArrayList<>(); //构造一个初始容量 ...

  5. Spring Boot源码简析 @EnableTransactionManagement

    相关阅读 Spring Boot源码简析 事务管理 Spring Boot源码简析 @EnableAspectJAutoProxy Spring Boot源码简析 @EnableAsync Sprin ...

  6. ffmpeg实战教程(十三)iJKPlayer源码简析

    要使用封装优化ijk就必须先了解ffmpeg,然后看ijk对ffmpeg的C层封装! 这是我看ijk源码时候的笔记,比较散乱.不喜勿喷~ ijk源码简析: 1.ijkplayer_jni.c 封装的播 ...

  7. 【Android项目】本地FM收音机开发及源码简析

    [Android项目]本地FM收音机开发及源码简析 目录 1.概述 2.收音机的基本原理 3.收音机其他信息 RDS功能 4.Android开发FM收音机源码解析 5.App层如何设计本地FM应用 6 ...

  8. Log-Pilot 源码简析

    Log-Pilot 源码简析 简单介绍 源码简析 Pilot结构体 Piloter接口 main函数 Pilot.Run Pilot.New Pilot.watch Pilot.processEven ...

  9. PhxRPC源码简析

    文章目录 前言 1. 背景 2. 特性 一.编译运行 1. 编译 2. 运行 二.整体框架 运行框架 代码框架 源码目录 生成代码 与svrkit的比较 三.network socket流 strea ...

最新文章

  1. 编写可调模板并使用自动调谐器
  2. Python实现1-9数组形成的结果为100的所有运算式
  3. 桥牌笔记:3NT做庄路线
  4. 阅读开源源码的正确姿势建议
  5. 一天学完spark的Scala基础语法教程教程三、循环结构(idea版本)
  6. TT 安装 之 AIX
  7. layer绑定回车事件(转)
  8. java异常标记_java.lang.RuntimeException:错误:0D0680A8:asn1编码例程:ASN1_CHECK_TLEN:错误的标记...
  9. (dijkstra记录路径)find the longest of the shortest
  10. JSF请求处理过程(一) FacesServlet初始化
  11. python windows系统管理_利用Python脚本管理Windows服务
  12. java编程——【Mybatis】之${}和#{}的区别
  13. json 插入数据_让繁琐的工作自动化——python处理JSON文件
  14. AI 时代,程序员从小白到小牛的发展攻略丨今晚直播送机械键盘!
  15. Operation not applicable
  16. SPSS Clementine 安装教程
  17. ITK实现DICM图像转换成BMP图像
  18. 数据结构与算法书籍汇总(从小白到大神)
  19. Java IO流的分类
  20. Android Camera聚焦区域和测光区域的设置

热门文章

  1. 企业开发需要的git提交和拉取代码(本地仓库和github演示)
  2. 开关 关闭_无论用什么品牌手机,这个开关要关闭,以免耗电又卡顿,抓紧试试...
  3. 图片合成gif_谈谈有哪些好用的制作GIF的方式
  4. python弹出框多一个空白框_Selenium+python3 应对多个弹出框存在(alert_is_present)判断和处理...
  5. js距离单位换算_英语中常用的度量衡等单位,与我们用的不一样,这些差异点快收藏...
  6. wxpython制作表格界面_[Python] wxPython 菜单栏控件学习总结(原创)
  7. php excelreader 中文,如何解决php excel reader导出excel中文乱码?
  8. 安装杀毒软件是保障计算机安全,安装杀毒软件是保障计算机安全的唯一措施
  9. 怎样取消连续包月自动续费_苹果手机连续包月会员怎么取消 设置iPhone解除应用自动续费...
  10. 一个小白如何创建MYSQL数据表_MySQL小白扫盲(二)--建表、添加、查询