1、模拟axios创建过程
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- <script src="node_modules/axios/dist/axios.js"></script>-->
</head>
<body>
<script>
function Axios (config) {
//初始化,创建defaults默认属性
this.defaults=config
this.interceptors={
request:{},
response:{}
}
}
//原型添加相关方法
Axios.prototype.request=function(config){
console.log('发送ajax请求,请求的类型为:'+config.method)
}
Axios.prototype.get=function(config){
//console.log('发行ajax请求')
return this.request({ method:'get'})
}
Axios.prototype.post=function(config){
//console.log('发行ajax请求')
return this.request({ method:'post'})
}
//声明一个函数
function createInstance (config) {
//实例化一个对象
//可以是context.get(),context.post(),但是不能当做函数来使用context()
let context=new Axios(config)
//创求请求对象函数,这时instance是一个函数,并且可以instance({})但这不能instance()直接用
let instance=Axios.prototype.request.bind(context)
//将Axios.prototype对象中的方法添加到instance函数对象中
Object.keys(Axios.prototype).forEach(key=>{
instance[key]=Axios.prototype[key].bind(context)
})
//为instance函数对象添加defaults属性和interceptors
Object.keys(context).forEach((key)=>{
instance[key]=context[key]
})
//console.dir(instance)
return instance
}
let axios=createInstance({method:'get'})
//发送请求
axios({method:'get'})//发送ajax请求,请求的类型为:get
axios({method:'post'})//发送ajax请求,请求的类型为:gost
axios.get({})//发送ajax请求,请求的类型为:get
axios.post({})//发送ajax请求,请求的类型为:gost
</script>
</body>
</html>
2、模拟axios发送请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>virtualsend</title>
</head>
<body>
<script>
//1、声明构造函数
function Axios(config){
this.config=config
}
Axios.prototype.request=function(config){
//发送请求
//创建一个promise对象
let promise=Promise.resolve(config)
//声明一个数组
let chains=[dispatchRequest,undefined]//undefined占位
//循环处理,调用then方法指定回到
let result=promise.then(chains[0],chains[1])
//返回这个promise的结果resualt对象,
return result
}
//2、dispatchRequest函数
function dispatchRequest(config){
//console.log('打印dispatchRequest')
//调用适配器发送请求
return xhrAdapter(config).then(response=>{
//console.log(response)
//响应的结果进行转换处理
return response
},error=>{
throw error
})
}
//3、adapter适配器
function xhrAdapter(config){
console.log('xhradpater适配器函数')
return new Promise((resolve,reject)=>{
//发送ajax请求
let xhr=new XMLHttpRequest()
xhr.open(config.method,config.url)
xhr.send()
//绑定事件
xhr.onreadystatechange=function () {
if (xhr.readyState==4){
if (xhr.status>=200 && xhr.status<300){
//成功的状态
resolve({
//配置对象:config
config:config,
data:xhr.response,
headers:xhr.getAllResponseHeaders(),
//xhr请求对象
request:xhr,
status:xhr.status,
statusText:xhr.statusText
})
}else{
reject(new Error('请求失败,失败的状态码为:'+xhr.status))
}
}
}
})
}
//4、创建axios函数
let axios=Axios.prototype.request.bind(null)
axios({
method:'get',
url:'http://localhost:3000/posts'
}).then(response=>{
console.log(response)
})
</script>
</body>
</html>
3、模拟axios实现拦截器
仅供参考,没有能够实现,当然也没看懂
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- <script src="node_modules/axios/dist/axios.js"></script>-->
</head>
<body>
<script>
function Axios (config) {
//初始化,创建defaults默认属性
this.defaults = config
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
}
}
//拦截管理器构造函数
function InterceptorManager () {
this.handlers = []
}
InterceptorManager.prototype.use = function (fulfilled, rejected) {
this.handlers.push(fulfilled)
this.handlers.push(rejected)
}
Axios.prototype.request = function (config) {
//创建一个promise对象
let promise=Promise.resolve(config)
//创建一个数组
const chains= [dispatchRequest,undefined]
//处理请求拦截器,将请求拦截器的回调,压入到chains的前面
this.interceptors.request.handlers.forEach(item=>{
chains.unshift((item.fulfilled,item.rejected))
})
//处理响应拦截器,将请求拦截器的回调,压入到chains的前面
this.interceptors.response.handlers.forEach(item=>{
chains.push((item.fulfilled,item.rejected))
})
// console.log(chains)
//遍历
while(chains.length>0){
promise=promise.then(chains.shift(),chains.shift())
}
}
//发送请求的代码
function dispatchRequest(config){
//返回一个promise对象
return new Promise((resolve, reject) => {
resolve({
status: 200,
statusText: '成功'
})
})
}
//创建实例
let context = new Axios({})
//创造axios函数
let axios = Axios.prototype.request.bind(context)
//将context属性config intereceptor添加至axios函数对象上
Object.keys(context).forEach(key => {
axios[key] = context[key]
})
axios.interceptors.request.use(function one (config) {
console.log('请求拦截器成功---111')//先进后执行,先进后出
//可以修改config的参数
config.params = { a: 100 }
return config
// throw '自己抛出的异常'
}, function (error) {
console.log('请求拦截器失败')
return Promise.reject(error)
})
axios.interceptors.request.use(function two (config) {
console.log('请求拦截器成功---222')//就近先执行,后进先出
//可以修改config的参数
config.timeout = 3000
return config
// throw '自己抛出的异常'
}, function (error) {
console.log('请求拦截器失败')
return Promise.reject(error)
})
//设置响应拦截器
axios.interceptors.response.use(function (response) {
console.log('响应拦截器成功---111')
return response
}, function (error) {
console.log('响应拦截器失败')
return Promise.reject(error)
})
axios.interceptors.response.use(function (response) {
console.log('响应拦截器成功----222')
return response
}, function (error) {
console.log('响应拦截器失败')
return Promise.reject(error)
})
axios({
method: 'get',
url: 'http://localhost:3000/posts'
})
</script>
</body>
</html>
4、模拟axios实现取消请求功能
也没实现,听不懂听不懂!!!!!!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test page</title>
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>-->
</head>
<body>
<div>
<h2>axios的基本使用</h2>
<button id="send_primary">发送get请求</button>
<button id="cacel_send">取消请求</button>
</div>
<script>
//创建构造函数
function Axios (config) {
this.config=config
}
//原型request方法
Axios.prototype.request=function (config) {
return dispatchRequest(config)
}
//dispatchRequest函数
function dispatchRequest (config) {
return xhrAdapter(config)
}
//xhrAdapter
function xhrAdapter (config) {
//发送ajax请求
return new Promise((resolve,reject)=>{
//实例化对象
const xhr=new XMLHttpRequest()
//初始化
xhr.open(config.method,config.url)
//发送
xhr.send()
xhr.onreadystatechange=function(){
if (xhr.readyState===4){
if (xhr.status>=200 && xhr.status<300){
//设置为成功的状态
resolve({
status:xhr.status,
statusText:xhr.statusText
})
}else{
reject(new Error('请求失败'))
}
}
}
//关于取消请求的处理
if (config.cancelToken){
//对cancelToken对象上的promise对象指定成功的回调
config.cancelToken.promise.then(value => {
xhr.abort()
})
}
})
}
//创建axios函数
const context=new Axios({})
const axios=Axios.prototype.request.bind(context)
//CancelToken构造函数
function CancelToken(excutor){
//声明一个变量
let resolvePromise
//为实例对象添加属性
this.promise=new Promise((resolve)=>{
//将resolve赋值给resolvePromise
resolvePromise=resolve
})
//调用excutor函数
excutor(function () {
//执行resolvePromise函数
resolvePromise()
})
}
//获取按钮以上为模拟实现的代码
const send_primary = document.querySelector('#send_primary')
const cacel_send = document.querySelector('#cacel_send')
//声明全局变量
let cancel = null
send_primary.addEventListener('click', function () {
if (cancel !== null) {
cancel()
console.log(cancel,"------")
}
//创建cancelToken的值
let cancelToken=new CancelToken(function (c) {
cancel = c//把c这个函数传给了全局变量cancel
})
axios({
method: 'get',
url: 'http://localhost:3000/posts',
//添加配置对象返回的是一个函数
// cancelToken:cancelToken
}).then(respone => {
console.log(respone)
cancel = null
console.log(cancel,"======")
})
})
cacel_send.addEventListener('click', function () {
cancel()
})
</script>
</body>
</html>
5、axios源码总结
1、axios和Axios的区别
- 从语法上来说axios不是Axios的实例
- 从功能上来说axios是Axios的实例
- axios是Axios.prototyp.request函数bind()返回的函数
- axios作为对象有Axios原型对象上的所有方法,有Axios对象上所有属性
2、instance和axios的区别
相同
- 都是一个能发任意请求的函数:request(config)
- 都有发特定请求的方法:get() post() put() delete()
- 都有默认配置和拦截器的属性:defaults 、interceptors
不同
默认配置很可能不一样
instance没有axios后面添加的一些方法:create()、 cancelToken() 、all()
3、aixos的请求/响应拦截器是什么
请求拦截器
- 在真正发送请求前执行的回调函数
- 可以对请求进行检查或配置进行特定处理
- 成功的回调函数,传递的默认是config(也必须是)
- 失败的回调函数,传递的默认值是error
响应拦截器
- 在请求得到响应后执行的回调函数
- 可以对响应数据进行特殊处理
- 成功的回调函数,传递的默认是response
- 失败的回调函数,传递的默认是error
4、aixos的请求/响应数据转换器是什么?
- 请求转换器:对请求头和请求体数据进行特定处理的函数
if(utils.isObject(data)){
setContentTypeifUnset(headers,'application/json;charset=utf-9'
return JSON.stringfy(data)
}
响应转换器:将响应体json字符串解析为js对象或数组的函数
response.data=JSON.parse(response.data)
5、response的整体结构
{
data,
status,
statusText,
headers,
config,
request
}
6、error的整体结构
{
message,
request,
response
}
7、如何取消未完成的请求
a、当配置了cancelToken对象时,保存cancel函数
- 创建一个用于将来终端请求的cancelPromise
- 并定义了一个用于取消请求的cancel函数
- 将cancel函数传递出去
b、调用cancel()取消请求
- 执行cacel函数,传入错误信息message
- 内部会让gcancelPromise变成成功,且成功的值为一个cancel对象
- 在canelPromise的成功回调中终端请求,并让发请求的promise失败,失败的reason为Cancel对象