Advertisement

你了解axios的原理吗?

阅读量:

一、axios的使用

关于axios的基本使用,上篇文章已经有所涉及,这里再稍微回顾下:

发送请求

复制代码
    import axios from 'axios';
    
    axios(config) // 直接传入配置
    axios(url[, config]) // 传入url和配置
    axios[method](url[, option]) // 直接调用请求方式方法,传入url和配置
    axios[method](url[, data[, option]]) // 直接调用请求方式方法,传入data、url和配置
    axios.request(option) // 调用 request 方法
    
    const axiosInstance = axios.create(config)
    // axiosInstance 也具有以上 axios 的能力
    
    axios.all([axiosInstance1, axiosInstance2]).then(axios.spread(response1, response2))
    // 调用 all 和传入 spread 回调
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/HqG5SamX9tuTIZBDirgcNJzwh1pQ.png)

请求拦截器

复制代码
    axios.interceptors.request.use(function (config) {
    // 这里写发送请求前处理的代码
    return config;
    }, function (error) {
    // 这里写发送请求错误相关的代码
    return Promise.reject(error);
    });
    
    
    javascript
    
    

响应拦截器

复制代码
    axios.interceptors.response.use(function (response) {
    // 这里写得到响应数据后处理的代码
    return response;
    }, function (error) {
    // 这里写得到错误响应处理的代码
    return Promise.reject(error);
    });
    
    
    javascript
    
    

取消请求

复制代码
    // 方式一
    const CancelToken = axios.CancelToken;
    const source = CancelToken.source();
    
    axios.get('xxxx', {
      cancelToken: source.token
    })
    // 取消请求 (请求原因是可选的)
    source.cancel('主动取消请求');
    
    // 方式二
    const CancelToken = axios.CancelToken;
    let cancel;
    
    axios.get('xxxx', {
      cancelToken: new CancelToken(function executor(c) {
    cancel = c;
      })
    });
    cancel('主动取消请求');
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/WUlQ7EAMTCBw8mvHpKuX2xZsiGND.png)

二、实现一个简易版axios

构建一个Axios构造函数,核心代码为request

复制代码
    class Axios {
    constructor() {
    
    }
    request(config) {
        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);
        })
    }
    }
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/QkdgDAjCeMtTqsR6lS7zFHhpcXV2.png)

导出axios实例

复制代码
    // 最终导出axios的方法,即实例的request方法
    function CreateAxiosFn() {
    let axios = new Axios();
    let req = axios.request.bind(axios);
    return req;
    }
    
    // 得到最后的全局变量axios
    let axios = CreateAxiosFn();
    
    
    javascript
    
    

上述就已经能够实现axios({ })这种方式的请求
下面是来实现下axios.method()这种形式的请求

复制代码
    // 定义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] || {}
            })
        }
    
    }
    })
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/xVK61Jt0Aaz8mgpfW7IeQwU524hr.png)

将Axios.prototype上的方法搬运到request上
首先实现个工具类,实现将b方法混入到a,并且修改this指向

复制代码
    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]
        }
      }
      
    }
      }
    }
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/iySKTpXnHMRxWV6gQ8qdz4uAPGJm.png)

修改导出的方法

复制代码
    function CreateAxiosFn() {
      let axios = new Axios();
      
      let req = axios.request.bind(axios);
      // 增加代码
      utils.extend(req, Axios.prototype, axios)
      
      return req;
    }
    构建拦截器的构造函数
    
    class InterceptorsManage {
      constructor() {
    this.handlers = [];
      }
    
      use(fullfield, rejected) {
    this.handlers.push({
      fullfield,
      rejected
    })
      }
    }
    实现axios.interceptors.response.use和axios.interceptors.request.use
    
    class Axios {
    constructor() {
        // 新增代码
        this.interceptors = {
            request: new InterceptorsManage,
            response: new InterceptorsManage
        }
    }
    
    request(config) {
     		...
    }
    }
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/cBkWiPVdXp9yIarhsCKRbw45DOuY.png)

执行语句axios.interceptors.response.use和axios.interceptors.request.use的时候,实现获取axios实例上的interceptors对象,然后再获取response或request拦截器,再执行对应的拦截器的use方法
把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;
    }
    现在request也有了interceptors对象,在发送请求的时候,会先获取request拦截器的handlers的方法来执行
    
    首先将执行ajax的请求封装成一个方法
    
    request(config) {
    this.sendAjax(config)
    }
    sendAjax(config){
    return new Promise(resolve => {
        const {url = '', method = 'get', data = {}} = config;
        // 发送ajax请求
        console.log(config);
        const xhr = new XMLHttpRequest();
        xhr.open(method, url, true);
        xhr.onload = function() {
            console.log(xhr.responseText)
            resolve(xhr.responseText);
        };
        xhr.send(data);
    })
    }
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/zwVOKvjy2dUD1fqGLx6cCEuWSbnB.png)

获得handlers中的回调

复制代码
    request(config) {
    // 拦截器和请求组装队列
    let chain = [this.sendAjax.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)
    })
    
    // 执行队列,每次执行一对,并给promise赋最新的值
    let promise = Promise.resolve(config);
    while(chain.length > 0) {
        promise = promise.then(chain.shift(), chain.shift())
    }
    return promise;
    }
    chains大概是['fulfilled1','reject1','fulfilled2','reject2','this.sendAjax','undefined','fulfilled2','reject2','fulfilled1','reject1']这种形式
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/6tdyfgPU1Oqu2CMT85lIK7hxQBGH.png)

这样就能够成功实现一个简易版axios

全部评论 (0)

还没有任何评论哟~