json-server网址:json-server - npm
axios既可以当做函数直接调用,也可以当做对象调用内部函数 – 先生成函数,再往函数原型上加方法
// 构造函数
function Axios(config){
// 初始化
this.defaults = config, //为了创建defaults的默认属性
// 拦截器
this.intercepters = {
request: {},
response: {}
}
}
/**
* 原型添加相关的方法
* axios 请求最终都是通过调用request方法去请求XMLHttpRequest
*/
Axios.prototype.request = function(config) {
console.log('发送 AJAX 请求,请求类型:' + config.method)
}
Axios.prototype.get = function(config) {
return this.request({method: 'GET'})
}
Axios.prototype.post = function(config) {
return this.request({method: 'POST'})
}
// 声明函数
function createInstance(config) {
/**
* 实例化一个对象
* 可以context.get() context.post(), 但是不能当做函数使用 context()
*/
let context = new Axios(config);
/**
* 创建请求函数
* instance 可以当做一个函数调用 instance(),
* 此时instance.get(), instance.post() 不能用
*/
let instance = Axios.prototype.request.bind(context);
// 将 Axios.prototype 对象中的方法添加到 instance 函数对象中
Object.keys(Axios.prototype).forEach(key => {
instance[key] = Axios.prototype[key].bind(context); // 让方法始终指向 context 实例
})
Object.keys(context).forEach(key => {
instance[key] = context[key]
})
return instance
}
let axios = createInstance()
axios({method: 'get'})
axios.get()
axios.post()
axios 是基于 promise 的http客户端,可在浏览器与node.js 服务器上发送请求
axios 是对 XMLHttpRequest的封装
axios 请求过程: axios 调用 request ,request 再调用 dispatch(适配器),dispatch 再调用 xhr。再逐步往回返回结果xhr -> dispatch -> request -> axios
// axios 发送请求, axios Axios.prototype.request bind
//1. 构造函数
function Axios(config){
this.config = config
}
Axios.prototype.request = function(config) {
// 创建一个永远为成功的promise
let promise = Promise.resolve(config)
// 生命一个数组 undefined 占位
let chains = [dispatchRequest, undefined]
// 调用 then 方法指定回调
let result = promise.then(chains[0], chains[1])
// 返回result 的 promise 结果
return result
}
//2.dispatchRequest函数
function dispatchRequest(config) {
// 调用适配器发送请求
return xhrAdapter(config).then(response => {
// 对响应的结果进行转换和处理
return response
},error => {
throw error
})
}
//3.创建适配器
function xhrAdapter(config){
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) return
if(xhr.status >= 200 && xhr.status < 300){
resolve({
config:config, // 配置对象
data: xhr.response, // 响应体
headers: xhr.getAllResponseHeaders(), // 响应头
request: xhr, // xhr 请求对象
status: xhr.status, // 响应状态码
statusText: xhr.statusText,
})
} else {
reject()
}
}
})
}
// 4.创建axios 函数
let axios = Axios.prototype.request.bind(null)
axios({
method: 'GET',
url: 'http://localhost:3000/posts'
}).then(response => {
console.log(response)
})
//1. 构造函数
function Axios(config){
this.config = config
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
}
}
// 发送请求
Axios.prototype.request = function(config) {
// 创建一个promise 对象
let promise = Promise.resolve(config)
const chains = [dispatchRequest, undefined]
/**
* 处理请求拦截器 - 重点
* 将请求拦截器,压入到 chains 的前面,request.handles=[]
* 响应拦截器,添加到 chains 的后面
*/
this.interceptors.request.handlers.forEach(item => {
chains.unshift(item.fulfilled, item.rejected)
})
this.interceptors.response.handlers.forEach(item => {
chains.push(item.fulfilled, item.rejected)
})
// 遍历
while(chains.length > 0) {
// shift() 取出数据第一个,会改变原数据
promise = promise.then(chains.shift(), chains.shift())
}
return promise
}
// 发送请求
function dispatchRequest(config){
return new Promise((resolve, reject) => {
resolve({
status:200,
statusText: 'ok'
})
})
}
// 拦截器管理器构造函数
function InterceptorManager() {
this.handlers = []
}
InterceptorManager.prototype.use = function(fulfilled, rejected){
this.handlers.push({fulfilled, rejected})
}
// 创建实例
let context = new Axios({})
// 创建axios 函数
let axios = Axios.prototype.request.bind(context)
// 将contex 属性config interceptor 添加至 axios 函数对象身上
Object.keys(context).forEach(key => {
axios[key] = context[key]
})
/**
* 设置请求拦截器, config 配置对象
* 请求输出结果:
* 请求拦截器-2号
* 请求拦截器-1号
* 响应拦截器-1号
* 响应拦截器-2号
* Axios.prototype.request 里的 chains.unshift 处理的结果
*/
axios.interceptors.request.use(function one(config){
console.log('请求拦截器-1号')
}, function(){})
axios.interceptors.request.use(function tow(config){
console.log('请求拦截器-2号')
}, function(){})
// 设置响应拦截器
axios.interceptors.response.use(function one(response){
console.log('响应拦截器-1号')
},function(){})
axios.interceptors.response.use(function tow(response){
console.log('响应拦截器-2号')
},function(){})
axios({
method: 'GET',
url: 'http://localhost:3000/posts'
}).then(response => {
console.log(response)
})
XMLHttpRequest 取消请求方法 - abort()
<body>
<button>发送</button>
<button>取消</button>
<script>
//1. 构造函数
function Axios(config){
this.config = config
}
// 发送请求
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 ) return
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(resolve => {
xhr.abort()
})
}
})
}
// CancelToken 构造函数
function CancelToken(executor){
// 声明一个变量
var resolvePromise;
// 为实例对象添加属性
this.promise = new Promise(resolve => {
// 将resolve 赋值给 resolvePromise 所以当调用 resolvePromise()等于 resolve() (指针指引类型)
resolvePromise = resolve
})
// 调用 executor 函数
executor(function(){
// 执行 resolvePromise 函数
resolvePromise()
})
}
// 创建axios 函数
const context = new Axios({})
const axios = Axios.prototype.request.bind(context)
// 以上为模拟实现的代码
const btns = document.querySelectorAll('button')
let cancel = null
btns[0].onclick = function() {
// 检测上一次请求是否已经完成
if(cancel !==null ){
cancel()
}
// 创建cancelToken的值
let cancelToken =new CancelToken(function(c){
// 将c赋值给 cancel ,因为c是函数,所以当调用 cancel()等于 c() (指针指引类型)
cancel = c
})
axios({
method: 'GET',
url: 'http://localhost:3000/posts',
// 添加配置对象的属性
cancelToken: cancelToken
}).then(response => {
console.log(response)
cancel = null
})
}
// 取消请求
btns[1].onclick = function() {
cancel()
}
</script>
</body>
1、语法上 axios 不是 Axios 的实例:
因为是先造实例,再造一个函数,再把实例原型上的方法,往函数原型上放,再把实例对象的身上的属性加到函数对象身上,最终再把函数返回axios
2、功能上 axios 是 Axios 的实例:
因为 axios 拥有 Axios 实例对象的方法,通过扩展的方式,把 Axios 实例对象的方法绑定到 axios 身上
3、axios 是 Axios.prototype.request 函数 bind() 返回的函数
4、axios 作为对象有 Axios 原型对象上的所有方法,有 Axios 对象上所有属性