axios专题(李强)02完结-模拟axios创建过程,模拟axios发送请求,模拟axios实现拦截器,模拟axios实现取消请求功能、axios源码总结

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对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值