字体包体积压缩实践

news2024/9/25 1:23:47

这篇博客针对axios库的核心代码做一个简要总结

一、关键步骤

1.创建axios对象

axios库导出的对象是一个已经被创建好的axios对象,它本质上是一个方法,可以直接接收一个config配置参数进行请求。在库的入口处,即可看到如下代码:

function createInstance(defaultConfig) {// 传入默认配置生成axios对象const context = new Axios(defaultConfig);// 本质是request方法,this上下文绑定contextconst instance = bind(Axios.prototype.request, context);// 将Axios原型上的属性复制到instanceutils.extend(instance, Axios.prototype, context, {allOwnKeys: true});// 将context上的属性复制到instanceutils.extend(instance, context, {allOwnKeys: true});// 暴露create工厂方法供外部创建自定义的axios对象instance.create = function create(instanceConfig) {return createInstance(mergeConfig(defaultConfig, instanceConfig));};return instance;
}
// 默认暴露的axios对象
const axios = createInstance(defaults); 

上述代码是创建默认axios对象的流程,这个对象上有Axios类的实例属性以及原型上的方法,且自身的是一个request方法,整个库最核心的也就是这个request方法。

2.请求

Axios的原型上存在很多辅助方法,如get,post,put等等,这些方法最终都会调用request方法,且默认设置了请求参数中的method属性,仅仅是一种封装的快捷调用方式。所以直接使用axios方法(axios的本质是一个方法),传入一个合法参数和使用axios.get等方法进行请求没有区别

二、Axios类

1.基础属性

axios类型的对象,存在2个基础属性

  • defaults:默认的请求参数
  • interceptors:请求和响应的拦截器

2.辅助方法

axios类型的对象存在很多辅助方法,如下:

  • delete
  • get
  • head
  • options
  • post
  • put
  • patch
  • postForm
  • patchForm
  • putForm

这些方法本质上都是request的封装,调用这些方法时,都会调用request方法,但相应的会预设置部分请求参数,如method和headers

3.request方法

方法定义如下:

 /** * Dispatch a request * * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults) * @param {?Object} config * * @returns {Promise} The Promise to be fulfilled */request(configOrUrl, config) {} 

这个方法是整个库的核心,它接收2个参数作为配置,并且返回一个Promise对象。内部流程如下:

(1)参数合并

if (typeof configOrUrl === 'string') {config = config || {};config.url = configOrUrl;
} else {config = configOrUrl || {};
}

config = mergeConfig(this.defaults, config); 

axios对象在创建时,会传入一个默认请求配置对象,这个对象会和请求时传入的请求配置进行合并处理。

(2)处理headers

// Set config.method
config.method = (config.method || this.defaults.method || 'get').toLowerCase();

// Flatten headers 将共用headers和特定请求的headers进行合并
const defaultHeaders = config.headers && utils.merge(config.headers.common,config.headers[config.method]
);
// 移除掉特定请求相关的header配置,这些配置的用途的限定类型请求带上特定的header,在网络中无用
defaultHeaders && utils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],function cleanHeaderConfig(method) {delete config.headers[method];}
);
// 合并header
config.headers = new AxiosHeaders(config.headers, defaultHeaders); 

合并后的对象需要进一步处理headers,一些headers配置只针对特定类型的请求,如get类型。

(3)运行执行队列

// 声明请求拦截器队列
const requestInterceptorChain = [];
let synchronousRequestInterceptors = true; //同步执行标识
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {return;}// 只要有一个拦截器配置上是异步模式,则整个流程异步synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;// 在定义拦截器时,会传入2个方法,一个是正常处理的回调,一个是异常时的回调,从对头放入拦截器队列// 注意此时是循环中,用的unshift,因此后定义的在前requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// 声明返回拦截器队列
const responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {// 同请求拦截器,但需要注意的时,用的push,因此后定义的在后responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});

let promise;
let i = 0;
let len;
// 如果是异步模式
if (!synchronousRequestInterceptors) {// dispatchRequest是最终请求时调用的方法,这个地方将请求拦截器队列,请求,返回拦截器队列拼接起来// 组成了一个异步调用队列const chain = [dispatchRequest.bind(this), undefined];chain.unshift.apply(chain, requestInterceptorChain);chain.push.apply(chain, responseInterceptorChain);len = chain.length;promise = Promise.resolve(config);while (i < len) {// 一个promise对象接受2个方法,一个resolve处理正常逻辑,一个reject处理异常逻辑// 这儿将调用方法两两一组,就组成了一个promise的调用链promise = promise.then(chain[i++], chain[i++]);}// 返回最后的那个promisereturn promise;
}
// 下面是同步模式
len = requestInterceptorChain.length;

let newConfig = config;

i = 0;
// 这儿本质和异步模式逻辑一样,都是两两一组,但promise的链式调用可以自动捕获异常状态的promise
// 这儿没有链式调用,则使用一个外包的try catch来处理这个异常 
// 需要注意同步模式仅限于请求拦截器队列和发送请求方法
while (i < len) {const onFulfilled = requestInterceptorChain[i++];const onRejected = requestInterceptorChain[i++];try {newConfig = onFulfilled(newConfig);} catch (error) {onRejected.call(this, error);break;}
}
// 发送请求
try {promise = dispatchRequest.call(this, newConfig);
} catch (error) {return Promise.reject(error);
}

i = 0;
len = responseInterceptorChain.length;
// 执行返回拦截器队列,此时异步执行
while (i < len) {promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);
}
// 返回最终promise
return promise; 

这一步是整个request设计的较为精妙的地方,注释已经比较详细,不在阐述。执行队列有2种执行模式,同步模式和异步模式,默认为异步模式。分别如下:

  • 异步模式

在异步模式下,细看代码,可以发现链式调用从promise = Promise.resolve(config);开始,并且config参数在请求拦截器的每一个调用环节都需要返回,作为下一个调用环节的入参,因为请求方法需要这个参数。如图所示,这就是一个Promise对象的链式调用,但请求方法所在的Promise没有reject回调,这在代码中是可以体现的,如下:

const chain = [dispatchRequest.bind(this), undefined]; 

其原因在于最后一个请求拦截器如果返回异常的Promise,则不请求。但由于代码没做容错处理,这儿会报出一个异常Promise没被捕获的错误。

  • 同步模式

同步模式和异步模式逻辑上相同,只是实现方式上有点差距,这儿就不在阐述了,同步模式本来就不是常用模式。

简单来说,就是request拦截器,request请求,response拦截器一起组成了一个执行队列。在异步模式下,队列里面每一个执行方法执行完成之后,会继续调用下一个执行方法。同步模式下,request拦截器和request请求会按顺序同步执行,但response拦截器会在请求返回后异步执行。本质上2种模式在调用的时间顺序上是一致的,这个异步和同步只在代码层面上的实现有所差别,这儿不是很理解为什么要设计一个同步模式,并且2种模式在请求有异常的情况下,其处理方式也有差别:

  • 异步模式:请求异常时,会被第一个返回拦截器的reject方法捕获,继续执行后续返回拦截器队列
  • 同步模式:请求异常时,直接返回一个异常的promise对象,不会执行返回拦截器队列

三、adpter适配器

Axios库是跨平台的,可以在node环境和web环境同时使用。因此内部有个"适配器"的概念,adpter是一个方法,一个请求本质上就是调用这个方法,方法必须返回一个Promise对象。请求配置中,甚至可以让我们自己去实现自己的适配器。

// `adapter` 允许自定义处理请求,这使测试更加容易。 // 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。

adapter: function (config) { /* ... */ }, 

如果提供了这么一个参数,那么将不会采用默认的适配器,直接使用提供的适配器。在上述执行队列中有一步是发送请求,这个适配器的调用就是在那个请求方法中

1.xhradpter

xhradpter适配器适用于web环境,利用XMLHttpRequest对象实现。本质上就是在操作一个XMLHttpRequest对象。

2.httpadpter

httpadpter适配器适用于node环境,利用node原生的http模块实现。

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/97944.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

非零基础自学Golang 第11章 文件操作 11.1 目录基本操作 11.1.2 创建目录 11.1.3 删除目录

非零基础自学Golang 文章目录非零基础自学Golang第11章 文件操作11.1 目录基本操作11.1.2 创建目录11.1.3 删除目录第11章 文件操作 11.1 目录基本操作 11.1.2 创建目录 Go标准库中的os库提供了平台无关性的操作系统功能接口。 创建目录时可以使用os库的如下接口&#xff1…

基于JSP的网络考试系统/在线考试系统的设计与实现

摘 要 网络考试系统是由高校的一个网络考试&#xff0c;按照章程自主开展网络考试系统。网络考试是实施素质教育的重要途径和有效方式&#xff0c;在加强校园文化建设、提高学生综合素质、引导学生适应社会、促进学生成才就业等方面发挥着重要作用&#xff0c;是新形势下有效凝…

[hadoop全分布部署]安装Hadoop、验证Hadoop①

&#x1f468;‍&#x1f393;&#x1f468;‍&#x1f393;博主&#xff1a;发量不足 个人简介&#xff1a;耐心&#xff0c;自信来源于你强大的思想和知识基础&#xff01;&#xff01; &#x1f4d1;&#x1f4d1;本期更新内容&#xff1a;安装Hadoop、验证Hadoop①&#…

【免杀前置课——Windows编程】十九、内存管理—堆,Windows如何管理内存数据?堆内存相关API

内存管理内存管理—堆Windows是如何管理内存数据的?堆内存管理相关API内存管理—堆 每个进程都有自己独立的4G内存空间&#xff0c;高2G操作系统内核使用&#xff0c;低 2G用户使用。 每个进程中我们使用的都是虚拟地址&#xff0c;虚拟机地址到物理地址的转换由操作系统内核…

1. 找出字符串中第一个匹配项的下标

给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示例 1&#xff1a; 输入&#xff1a;haystack &qu…

图形学中那些你需要知道的变换概念

前言 在前面的OpenGL ES 教程中&#xff0c;随着教程的进展&#xff0c;我们介绍并使用过很多变换矩阵&#xff0c;但没有系统总结过图形学涉及到的种种变换&#xff0c;因此这篇文章再次回顾“变换”这个主题。 变换 通俗来讲&#xff0c;所谓的变换就像编程中调用一个函数…

非零基础自学Golang 第12章 接口与类型 12.1 接口定义

非零基础自学Golang 文章目录非零基础自学Golang第12章 接口与类型12.1 接口定义12.1.1 接口的定义12.1.2 鸭子类型第12章 接口与类型 在使用接口时&#xff0c;我们经常会遇到这样一个问题&#xff1a;如何判断一个接口的类型&#xff1f;这时&#xff0c;我们就需要学习使用…

Dubbo 4 Dubbo 高级特性 4.1 dubbo-admin 管理平台 4.1.3 dubbo-admin的简单使用

Dubbo 【黑马程序员Dubbo快速入门&#xff0c;Java分布式框架dubbo教程】 4 Dubbo 高级特性 文章目录Dubbo4 Dubbo 高级特性4.1 dubbo-admin 管理平台4.1.3 dubbo-admin的简单使用4.1 dubbo-admin 管理平台 4.1.3 dubbo-admin的简单使用 注意:Dubbo Admin【服务Mock】【服务…

几个字就能生成画作,AIGC的时代即将到来

一、前言 最近AI绘画、聊天、代码生成可以说是刮起了一阵风&#xff0c;席卷了互联网。各大网站都在疯狂刷屏相关的内容&#xff0c;也收到了各界的热烈的关注。无论是AI绘画还是聊天这类的技术都属于同一个领域&#xff1a;人工智能生成内容&#xff08;AIGC&#xff09; 小伙…

SAP UI5 Mock Server 在响应 OData 请求时的单步调试

SAPUI5 中包含的模拟服务器模仿 OData V2 后端调用。 它模拟 OData 提供程序并且完全基于客户端&#xff0c;这意味着不需要与远程主机的网络连接。 它拦截对服务器的 HTTP 调用&#xff0c;并向客户端提供伪造的输出。 所有这些对于数据绑定和 OData 模型的使用都是透明的&…

【Python百日进阶-数据分析】Day131 - plotly柱状图(条形图):go.bar()实例2

文章目录4.2.14 多类别轴型条形图4.2.15 基本水平条形图4.2.16 彩色水平条形图4.2.17 条形图的调色板4.2.18 带直线图的条形图4.3 Dash中的条形图4.2.14 多类别轴型条形图 如果记录道具有x或y阵列&#xff0c;则轴类型将自动推断为多类别。 import plotly.graph_objects as g…

Dubbo 4 Dubbo 高级特性 4.2 Dubbo 常用高级配置 4.2.2 地址缓存 4.2.3 超时

Dubbo 【黑马程序员Dubbo快速入门&#xff0c;Java分布式框架dubbo教程】 4 Dubbo 高级特性 文章目录Dubbo4 Dubbo 高级特性4.2 Dubbo 常用高级配置4.2.2 地址缓存4.2.3 超时4.2 Dubbo 常用高级配置 4.2.2 地址缓存 【一个问题】 如果 注册中心挂了&#xff0c;服务是否可以…

计算机毕业设计ssm+vue基本微信小程序的垃圾分类系统

项目介绍 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代,垃圾分类小程序就是信息时代变革中的产物之一。 任何系统都要遵循系统…

uni-app卖座电影多端开发纪实(四):用户交互

@Tabs切换 + 分页加载 Tabs切换效果图 正在加载效果图 没有更多效果图 @uView组件使用 uView/Tabs的使用 uView/Tabs文档 先搂一眼! uView/loadMore的使用 uView/loadMore文档先搂一眼! @准备工作 电影条目组件封装 components/FilmItem.vue

2022/12/17 mysql 索引基本原理解读

1什么是索引 索引是帮助MySQL 高效获取数据的数据结构&#xff0c;通过使用索引可以在查询的过程中&#xff0c;使用优化隐藏器&#xff0c;提高系统的性能。 https://www.cs.usfca.edu/~galles/visualization/Algorithms.html 优势 类似于书籍的目录索引&#xff0c;提高数…

java缓存模块,ehcache/guava cache/自定义spring的CacheManager/自定义缓存

如ehcache,guava cache,redis 也有将ehcache,guava cache分级为单机缓存 将redis分为分布式缓存 ehcache官网:https://www.ehcache.org/ 这里主要说下ehcache和guava cache 单独使用ehcache(当然真正企业开发并不会单独使用ehcache,而是会和Spring或者SpringBoot集成使用) …

什么是建筑中的“光储直柔”

建筑“光储直柔”与零碳电力如影随形&#xff08;2021&#xff09; 《2030 年前碳达峰行动方案》&#xff08;国发〔2021〕23 号&#xff09;中明确提出&#xff1a;提高建筑终端电气化水平&#xff0c;建设集光伏发电、储能、直流配电、柔性用电于一体的“光储直柔”建筑。到 …

广告、推荐模型加速策略整理

当我们尝试那些开箱即用的GPU服务时&#xff0c;很快意识到在经济高效地利用GPU运行推荐模型服务之前需要对其优化。我们首先使用分析工具来分析在模型推理过程中发生了什么&#xff0c;在仔细观察分析结果时&#xff0c;我们注意到时间线上有大量的小CUDA Kernel在执行。 这是…

[附源码]Python计算机毕业设计Django汽配管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

linux内核内存管理-brk系统调用

【推荐阅读】 深入linux内核架构--进程&线程 浅谈linux 内核网络 sk_buff 之克隆与复制 浅析linux内核网络协议栈--linux bridge 尽管可见度不高&#xff0c;brk也许是最常使用的系统调用了&#xff0c;用户进程通过它向内核申请空间。人们常常并不意识到在调用brk&…