自从Axios成功打入Vue全家桶之后,便开始火的一塌糊涂!截止到目前,其在github上的star即将突破80k!可以说Axios是当下前端界最流行的ajax请求库,可(jue)能(dui)没有之一!
即然Axios人气如此之高,那么阅读并研究它的源码也是非常有必要的,因为这样不仅可以让自己少走很多弯路,还会对作者多年的编程思想以及经验进行猎取,从中抽象出一些架构及模式性的高级内容,最终提高自己的实现能力和技巧,让自己变得更加强大!
(啰嗦句:阅读源码的换确确可以提升自身的编码水平,但需要你拥有一定相关经验基础以及相对领域的认知,否则看源码绝对是在浪费时间!为什么?因为你看不懂!)
本系列文章将会对Axios源码思想进行精简提炼,从而将大家所关心的一些内部原理问题进行解答。
一、封装一个简易版本的xhr + promise的异步ajax请求库
由于axios是一个基于xhr + promise的异步ajax请求库,所以咱们可以先单纯的封装一个:

function axios(config){// 将请求方式全部转为大写const method = (config.method || "get").toUpperCase();// 返回Promisereturn new Promise((resolve,reject)=>{// 声明xhrconst xhr = new XMLHttpRequest();// 定义一个onreadystatechange监听事件xhr.onreadystatechange = function () {// 数据全部加载完成if(xhr.readyState === 4){// 判断状态码是否正确if(xhr.status >= 200 && xhr.status < 300){// 得到响应体的内容const data = JSON.parse(xhr.responseText);// 得到响应头const headers = xhr.getAllResponseHeaders();// request 即是 xhrconst request = xhr;// 状态码const status = xhr.status;// 状态码的说明const statusText = xhr.statusTextresolve({config,data,headers,request,status,statusText});}else{reject("请求失败"+xhr.status+xhr.statusText);}}}// 判断是否拥有params,且类型为objectif(typeof config.params === "object"){// 将object 转为 urlencoded const arr = Object.keys(config.params);const arr2 = arr.map(v=>v+"="+config.params[v]);const url = arr2.join("&");config.url +=  "?" + url;}xhr.open(method,config.url);// post put patchif(method === "POST" || method === "PUT" || method === "PATCH"){if(typeof config.data === "object")xhr.setRequestHeader("content-type","application/json");else if(typeof config.data === "string")xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");xhr.send(JSON.stringify(config.data));}else{xhr.send();}})
}

以上代码实现了axios(config)直接发起请求,例如:

axios({method:"delete",url:"data.json"
}).then(res=>console.log(res))

但是,如果我想通过axios.get(url[, config])axios.delete(url[, config])axios.post(url[, data[, config]])等请求方式就行不通了。
二、封装request
通过阅读源码得到一些启示:源码中有一个名为Axios的构造函数,而我们的xhr + promise封装在Axios.prototype.request函数中。另外我们所使用的axios.getaxios.post等也都是定义在Axios.prototype中。
根据这些启示将代码调整为:

// 构造函数
function Axios(){}
Axios.prototype.request = function (config) {// 将请求方式全部转为大写const method = (config.method || "get").toUpperCase();// 返回Promisereturn new Promise((resolve,reject)=>{// 声明xhrconst xhr = new XMLHttpRequest();// 定义一个onreadystatechange监听事件xhr.onreadystatechange = function () {// 数据全部加载完成if(xhr.readyState === 4){// 判断状态码是否正确if(xhr.status >= 200 && xhr.status < 300){// 得到响应体的内容const data = JSON.parse(xhr.responseText);// 得到响应头const headers = xhr.getAllResponseHeaders();// request 即是 xhrconst request = xhr;// 状态码const status = xhr.status;// 状态码的说明const statusText = xhr.statusTextresolve({config,data,headers,request,status,statusText});}else{reject("请求失败"+xhr.status+xhr.statusText);}}}// http://127.0.0.1/two?a=1&b=2// 判断是否拥有params,且类型为objectif(typeof config.params === "object"){// 将object 转为 urlencoded const arr = Object.keys(config.params);const arr2 = arr.map(v=>v+"="+config.params[v]);const url = arr2.join("&");config.url +=  "?" + url;}xhr.open(method,config.url);// post put patchif(method === "POST" || method === "PUT" || method === "PATCH"){if(typeof config.data === "object")xhr.setRequestHeader("content-type","application/json");else if(typeof config.data === "string")xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");xhr.send(JSON.stringify(config.data));}else{xhr.send();}})
}
Axios.prototype.get = function (url,config) {return this.request({method:"get",url,...config});
}
Axios.prototype.post = function (url,data) {return this.request({url,method:"post",data})
}
// 其它请求delete,patch省略
export default new Axios();

这样我们终于可以通过axios.get(url[, config])axios.post(url[, data[, config]])请求数据了。

import axios from "./Axios.js";
axios.post("data.json",{a:1,b:2
}).then(res=>{console.log(res);
})
axios.get("data.json",{params:{a:1,b:2}
}).then(res=>{console.log(res);
})

但是axios(config)又不行了。
三、createInstance函数
继续攻读源码发现:axios 本质不是Axios构造函数的实例,而是一个函数名字为createInstance的函数对象,在该函数中实例化了Axios。也就是说:我们所使用的axios并不是Axios的实例,而是Axios.prototype.request函数bind()返回的函数。

function createInstance(defaultConfig){const context = new Axios(defaultConfig);Axios.prototype.request.bind(context);// instance 是一个函数。该函数是request,并且将this指向context.var instance = Axios.prototype.request.bind(context);// 等同于上面那行代码// 将Axios的原型方法放置到instance函数属性中Object.keys(Axios.prototype).forEach(method=>{instance[method] = Axios.prototype[method].bind(context)})Object.keys(context).forEach(attr=>{instance[attr] = context[attr];})return instance;
}
export default createInstance;

四、axios实现多种请求方式原理完整代码:

// 构造函数
function Axios(){}
Axios.prototype.request = function (config) {// 将请求方式全部转为大写const method = (config.method || "get").toUpperCase();// 返回Promisereturn new Promise((resolve,reject)=>{// 声明xhrconst xhr = new XMLHttpRequest();// 定义一个onreadystatechange监听事件xhr.onreadystatechange = function () {// 数据全部加载完成if(xhr.readyState === 4){// 判断状态码是否正确if(xhr.status >= 200 && xhr.status < 300){// 得到响应体的内容const data = JSON.parse(xhr.responseText);// 得到响应头const headers = xhr.getAllResponseHeaders();// request 即是 xhrconst request = xhr;// 状态码const status = xhr.status;// 状态码的说明const statusText = xhr.statusTextresolve({config,data,headers,request,status,statusText});}else{reject("请求失败"+xhr.status+xhr.statusText);}}}// http://127.0.0.1/two?a=1&b=2// 判断是否拥有params,且类型为objectif(typeof config.params === "object"){// 将object 转为 urlencodedconst arr = Object.keys(config.params);const arr2 = arr.map(v=>v+"="+config.params[v]);const url = arr2.join("&");config.url +=  "?" + url;}xhr.open(method,config.url);// post put patchif(method === "POST" || method === "PUT" || method === "PATCH"){if(typeof config.data === "object")xhr.setRequestHeader("content-type","application/json");else if(typeof config.data === "string")xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");xhr.send(JSON.stringify(config.data));}else{xhr.send();}})
}
Axios.prototype.get = function (url,config) {return this.request({method:"get",url,...config});
}
Axios.prototype.post = function (url,data) {return this.request({url,method:"post",data})
}
function createInstance(defaultConfig){const context = new Axios(defaultConfig);Axios.prototype.request.bind(context);// instance 是一个函数。该函数是request,并且内部this指向context.var instance = Axios.prototype.request.bind(context);// 等同于上面那行代码// 将Axios的原型方法放置到instance函数属性中Object.keys(Axios.prototype).forEach(method=>{instance[method] = Axios.prototype[method].bind(context)})Object.keys(context).forEach(attr=>{instance[attr] = context[attr];})return instance;
}
export default createInstance;

axios post json_助你解析Axios原理之一:如何实现多种请求方式相关推荐

  1. axios post object object_深入学习Axios源码(构建配置)

    axios是我们日常代码中常用的一个http库,它可以用来在浏览器或者node.js中发起http请求:它强大的功能和简单易用的API受到了广大前端童鞋们的青睐:那么它内部是如何来实现的呢,让我们走进 ...

  2. vue+axios+qs序列化 “三步解析”【含demo实例】- 代码篇

    文章目录 qs序列化:是什么?为什么?怎么办?`实例截图参考` 一.`(简单了解)` · `三步解析 ` 序列化是一种用来处理对象流的机制: 对象.文件.数据,有许多不同的格式,很难统一传输和保存 序 ...

  3. axios post body参数_vue之axios封装

    在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中.他有很多优秀的特性,例如拦截请求和响应.取消请求.转换js ...

  4. axios队列 vue_(十三 )Vue 封装axios(四种请求)及相关介绍

    Vue 封装axios(四种请求)及相关介绍 首先axios是基于promise的http库 promise是什么? 1.主要用于异步计算 2.可以将异步操作队列化,按照期望的顺序执行,返回符合预期的 ...

  5. axios拦截器_78.1K 的 Axios 项目有哪些值得借鉴的地方

    Axios 是一个基于 Promise 的 HTTP 客户端,同时支持浏览器和 Node.js 环境.它是一个优秀的 HTTP 客户端,被广泛地应用在大量的 Web 项目中. 由上图可知,Axios ...

  6. ajax jq 图片上传请求头_全面分析前端的网络请求方式:Ajax ,jQuery ,axios,fetch

    链接:https://juejin.im/post/5c9ac607f265da6103588b31 一.前端进行网络请求的关注点 大多数情况下,在前端发起一个网络请求我们只需关注下面几点: 传入基本 ...

  7. 浏览器解析JavaScript原理

    1.浏览器解析JavaScript原理特点: 1.跨平台  2.弱类型 javascript 定义的时候不需要定义数据类型,数据类型是根据变量值来确定的.    var a = 10; 数字类型   ...

  8. gcc 删除elf_ELF文件格式解析器 原理 + 代码

    本文为看雪论坛精华文章 看雪论坛作者ID:菜鸟m号 附件链接:[原创] ELF文件格式解析器 原理 + 代码 写在前面: 读<Linux二进制>,发现作者对 ELF文件格式部分并没有做详细 ...

  9. Kubernetes应用部署模型解析(原理篇)

    2019独角兽企业重金招聘Python工程师标准>>> Kubernetes应用部署模型解析(原理篇) 博客分类: Kubernetes [编者按]Kubernetes可用来管理Li ...

最新文章

  1. java 枚举转byte_如何在java中将一个枚举转换为另一个枚举?
  2. linux mysql设置开机启动脚本_linux下添加oracle自启动脚本
  3. 字体 素材_最新2019毛笔书法字体素材合集!自创字体解决版权,甲方看都说好...
  4. Spring构造方法注入类型歧义
  5. Object调用静态方法
  6. android代码怎么打成蓝色,如何将我的Android应用程序的重音颜色从蓝色更改为其他颜色...
  7. Spring重点面题总结
  8. 十款开源的数据库管理工具
  9. 浅析麒麟信安云几大优势之“安全性”篇
  10. 反编译DLL。并且修改DLL内容
  11. android 优酷 api接口,腾讯优酷网站视频引用接口
  12. css 小尖角,CSS3之尖角标签
  13. Android渠道包构建流程
  14. linux drcom客户端配置
  15. 报错:Warning: To load an ES module, set “type“: “module“ in the package.json or use the .mjs extension
  16. 【lua/aviutl】小型倒计时
  17. Windows 无线上外网并通过共享让其它电脑用有线连接后也能上外网
  18. JAVA 制作给定时间倒计时器
  19. [GO]学习新语言之卡塔练习--猜数字
  20. 小森生活服务器维护公告,小森生活2021年5月11日停服更新公告

热门文章

  1. java实验指导答案华软_Java核心编程技术实验指导教程
  2. java fork join demo_Fork/Join框架 demo
  3. b站怎么删自己的专栏_麦当劳B站直播翻车,品牌B站营销到底应该怎么做?
  4. php简介及其发展,PHP 简介
  5. SylixOS中AARCH64跳转表实现原理
  6. Error running app: Default Activity Not Found
  7. 基于 vue + zhengAdmin 的一套后台模板
  8. 服务不支持chkconfig
  9. 使用OUTPUT从句从SQL Server表删除和归档大量记录
  10. 不使用控件的分页实现分页(更灵活)