手写简易版axios

axios的调用-index.html

  • axios的调用有不同的形式,01. axios(config) 02. axios.method(url, data? , config? )
  • 要实现一个函数方法同时拥有属性,以下实现了一个工具类utils.extend

<script type="text/javascript" src="./myaxios.js"></script>

<body>
  <button class="btn">点我发送请求</button>
  <script>

    document.querySelector('.btn').onclick = function() {
      // 分别使用以下方法调用,查看myaxios的效果
      
      axios.get('/getAxios?name=xiaoxiao').then(res => {
        console.log('getAxios 成功响应', res);
      }, err => {})

      // axios.post('/postAxios', {
      //   name: '小美post'
      // }).then(res => {
      //   console.log('postAxios 成功响应', res);
      // })

      // axios({
      //   method: 'get',
      //   url: '/getAxios'
      // }).then(res => {
      //   console.log('getAxios 成功响应', res);
      // })
    }
  </script>
</body>
</html>

myaxios.js实现axios和axios[method]

  • 要实现axios方法,axios.get, axios.post …方法
  • eg: function axios(){}; axios[‘get’] = function(){}…
// 工具方法,实现b的方法混入a;
const utils = {
  extend(a,b, context) {
    for(let key in b) {
        if (typeof b[key] === 'function') {
          a[key] = b[key].bind(context);
        }
    }
  }
}

// 定义Axios类,实现一个request方法,该方法会执行ajax请求。最终返回的就是Axios实例上的request方法。
class Axios {
  constructor() {
    this.test = 'zml'
  }

  request(config) {
    console.log('执行request方法, this.test:'+this.test);
    return new Promise(resolve => {
      const {url = '', method = 'get', data = {}} = config;
      // 发送ajax请求
      const xhr = new XMLHttpRequest();
      xhr.open(method, url, true);
      xhr.onload = function() {
        console.log(xhr.responseText)
        resolve(xhr.responseText);
      }
      xhr.send(data);
    })
  }
}


// 定义get,post...方法,挂在到Axios原型上
const methodsArr = ['get', 'delete', 'head', 'options', 'put', 'patch', 'post'];
methodsArr.forEach(met => {
  Axios.prototype[met] = function() {
    console.log('执行'+met+'方法');
    // 处理单个方法
    if (['get', 'delete', 'head', 'options'].includes(met)) { // 2个参数(url[, config])
      return this.request({
        method: met,
        url: arguments[0],
        ...arguments[1] || {}
      })
    } else { // 3个参数(url[,data[,config]])
      return this.request({
        method: met,
        url: arguments[0],
        data: arguments[1] || {},
        ...arguments[2] || {}
      })
    }
   
  }
})

// 最终导出axios的方法-》即实例的request方法
function CreateAxiosFn() {
  let axios = new Axios();
  
  let req = axios.request.bind(axios);
  // 混入方法, 处理axios的request方法,使之拥有get,post...方法
  utils.extend(req, Axios.prototype, axios)
  utils.extend(req, axios)
  return req;
}

// 得到最后的全局变量axios
let axios = CreateAxiosFn();

带拦截器的调用- index.html

<script>
    // 拦截器
      axios.interceptors.request.use(function (config) {
        console.log('拦截😊1');
        return config;
      }, function (error) {
        return Promise.reject(error);
      });

      axios.interceptors.request.use(function (config) {
        console.log('拦截2🏀');
        return config;
      }, function (error) {
        return Promise.reject(error);
      });
      
      axios.interceptors.response.use(function (response) {
        console.log('响应拦截1🌹',response);
        return response;
      }, function (error) {
        return Promise.reject(error);
      });
</script>

axios实现拦截器

  • 定义一个拦截器管理器,成对(一组成功和失败为一对)存储拦截器方法
// 第二步,实现拦截器
class InterceptorsManage {
  constructor() {
    this.handlers = [];
  }

  use(fullfield, rejected) {
    this.handlers.push({
      fullfield,
      rejected
    })
  }
}
  • 构造函数Axios初始化时候定义属性: interceptors
class Axios {
  constructor() {
    this.test = 'zml'
    this.interceptors = {
      request: new InterceptorsManage,
      response: new InterceptorsManage
    }
  }
}
  • request方法调用时候,组装(拦截器+请求方法)队列,之前的请求方法,提取出去。
request(config) {
    // 拦截器和请求组装队列
    let chain = [this.xhrFn.bind(this), undefined] // 成对出现的,失败回调暂时不处理

    // 请求拦截
    this.interceptors.request.handlers.forEach(interceptor => {
      chain.unshift(interceptor.fullfield, interceptor.rejected)
    })

    // 响应拦截
    this.interceptors.response.handlers.forEach(interceptor => {
      chain.push(interceptor.fullfield, interceptor.rejected)
    })

    console.log(chain);
}

xhrFn(config) {
    console.log('执行request方法, this.test:'+this.test);
    return new Promise(resolve => {
      const {url = '', method = 'get', data = {}} = config;
      // 发送ajax请求
      const xhr = new XMLHttpRequest();
      xhr.open(method, url, true);
      xhr.onload = function() {
        console.log(xhr.responseText)
        resolve(xhr.responseText);
      }
      xhr.send(data);
    })
  }

  • 拿到的队列依次执行
request(config) {
    // ...组装队列方法
    console.log(chain);
    
    // 执行队列,每次执行一对,并给promise赋最新的值
    let promise = Promise.resolve(config);
    while(chain.length > 0) {
     promise = promise.then(chain.shift(), chain.shift())
    }
    return promise;
  }
  • 工具方法utils.extend完善
// 方法也要混入进去
const utils = {
  extend(a,b, context) {
    for(let key in b) {
      if (b.hasOwnProperty(key)) {
        if (typeof b[key] === 'function') {
          a[key] = b[key].bind(context);
        } else {
          a[key] = b[key]
        }
      }
      
    }
  }
}
  • 创建axios的方法完善
function CreateAxiosFn() {
  let axios = new Axios();
  
  let req = axios.request.bind(axios);
  // 混入方法, 处理axios的request方法,使之拥有get,post...方法
  utils.extend(req, Axios.prototype, axios)
  // 混入属性,处理axios的request方法,使之拥有axios实例上的所有属性
  utils.extend(req, axios)
  return req;
}

完整代码链接

github地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值