axios源码解析

1.axios是什么?有什么优点?用法?

axios 是通过 Promise 实现对 ajax 技术的一种封装,在浏览器使用原生 XHR 对象,在node使用 http 模块

axios优点:

  1. 从浏览器中创建 XMLHttpRequest
  2. 从 node.js 创建 http 请求
  3. 支持 Promise API
  4. 转换请求和响应数据
  5. 支持请求/响应拦截器
  6. 自动转换JSON数据

axios 既可以当函数调用,也可以当对象使用 ( axios({}) axios.get() )

  1. 请求方法的别名
    axios(config) (通用/最本质的发任意类型请求的方式)
    axios(url[, config]) (可以只指定url发get请求)
    axios.request(config) (等同于 axios(config) )
    axios.get(url[, config]) (发get请求)
    axios.post(url[, data[, config]]) (发post请求)
    axios.put(url[, data[, config]]) (发put请求)
    axios.delete(url[, config]) (发delete请求)
    axios.head(url[, config])
    axios.patch(url[, data[, config]])

  2. 拦截器
    axios.defaults.xxx (请求的默认全局配置)
    axios.interceptors.request.use() (添加请求拦截器)
    axios.interceptors.response.use() (添加响应拦截器)

  3. 创建实例和一些取消请求方法
    axios.create([config]) (创建一个新的axios实例 注意:它没有下面的功能)
    axios.all(iterable) (用于批量执行多个异步请求)
    axios.spread(callback) (用来指定接收所有成功数据的回调函数的方法)
    axios.Cancel() (用于创建取消请求的错误对象)
    axios.isCancel() (是否是一个取消请求的错误)
    axios.CancelToken() (用于创建取消请求的token对象)

2.axios源码解析

  1. cancel (定义取消功能)
  2. core
    Axios.js (axios的核心主类)
    dispatchRequest.js (用来调用http请求适配器方法发送请求)
    InterceptorManager.js (拦截器构造函数)
    settle.js (根据http响应状态,改变Promise的状态)
  3. helpers (一些辅助方法)
  4. adapters
    http.js (实现http适配器)
    xhr.js (实现xhr适配器)
  5. axios.js (对外暴露接口)
  6. defaults.js (默认配置)
  7. utils.js (公用工具)

axios.js文件,创建实例对象,对外暴露出去

  1. 创建 Axios 实例 context,并且将默认配置传入
  2. 创建一个 instance 返回的是一个 wrap 函数,该函数传入Axios.prototype.request方法和context实例对象
  3. 所以 axios() = instance() = wrap() = Axios.prototype.request.call(context)
  4. 然后使用 extend 方法,将 Axios.prototype 上的属性方法拷贝 instance
  5. 所以 axios.get() = instace.get = Axios.prototype.get() 在给方法中 return this.request(),所以最后axios.get() = Axios.prototype.request() 还是调用了这个方法
  6. 最后将 context 实例对象拷贝给 instance
// axios.ja 入口文件
var Axios = require('./core/Axios');
var defaults = require('./defaults');
function createInstance(defaultConfig) {
    // 创建 axios 实例
    var context = new Axios(defaultConfig);
    // bind返回wrap方法,而不是axios实例
    var instance = bind(Axios.prototype.request, context);
    // extend 将 Axios.prototype 拷贝给 instance
    // axios = Axios.prototype => axios.get = Axios.prototype.get
    // 这也是为什么可以使用 axios.get
    utils.extend(instance, Axios.prototype, context);
    utils.extend(instance, context);
    return instance;
}
// 创建实例
var axios = createInstance(defaults);
axios.Axios = Axios;
// 工厂模式 创建新的实例 用户可以自定义一些参数
axios.create = function create(instanceConfig) {
    return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

utils.js文件,一些工具方法,展示几个比较重要的

// utils.js 文件中几个重要方法
// forEach 用来遍历对象
// forEach 用来循环 obj 中对象,然后在 fn 中可以拿到 obj 中的 key,val,obj
function forEach(obj, fn) {
    if (obj === null || typeof obj === 'undefined') { return; } 
    if (typeof obj !== 'object') { obj = [obj]; }
    if (isArray(obj)) {
        for (var i = 0, l = obj.length; i < l; i++) {
            fn.call(null, obj[i], i, obj);
        }
    } else {
        for (var key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
                fn.call(null, obj[key], key, obj);
            }
        }
    }
}

// extend 用于拷贝对象
// 将b对象中的 key val 赋给 a,然后返回a
function extend(a, b, thisArg) {
    forEach(b, function assignValue(val, key) {
        if (thisArg && typeof val === 'function') {
            a[key] = bind(val, thisArg);
        } else {
            a[key] = val;
        }
    });
    return a;
}

// helpers/bind.js   bind函数
// 返回的是一个函数,该函数用来改变 this 的指向
module.exports = function bind(fn, thisArg) {
    return function wrap() {
        var args = new Array(arguments.length);
        for (var i = 0; i < args.length; i++) {
            args[i] = arguments[i];
        }
        return fn.apply(thisArg, args);
    };
};

defaults.js文件,用来导出默认配置

// defaults.js 文件中可以找到
function getDefaultAdapter() {
    var adapter;
    // 这里判断运行环境,给 adapter 赋值,浏览器就赋值xhr对象,node环境就赋值http对象
    if (typeof XMLHttpRequest !== 'undefined') {
        adapter = require('./adapters/xhr');
    } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
        adapter = require('./adapters/http');
    }
    return adapter;
}
// 将 adapter 用对象包起来导出,当然还有默认配置
var defaults = {
    adapter: getDefaultAdapter(),
    // 省略
}
module.exports = defaults;

core/Axios.js

// context 的构造函数
function Axios(instanceConfig) {
    // 将 adapter 和一些默认配置储存起来
    this.defaults = instanceConfig;
    // 将包含 请求/响应拦截器 的对象 保存到 interceptors 上
    this.interceptors = {
        request: new InterceptorManager(),
        response: new InterceptorManager()
    };
}

// 请求方法
Axios.prototype.request = function request(config) {
    // chain是一个数组,用来模拟堆栈顺序,dispatchRequest是发送请求模块
    var chain = [dispatchRequest, undefined];
    // 等价于 var promise = new Promise( (resolve)=> resolve(config) )
    var promise = Promise.resolve(config);
    // 请求拦截器将方法插入数组头部
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
        chain.unshift(interceptor.fulfilled, interceptor.rejected);
    });
    // 相应拦截器将方法插入数组尾部
    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
        chain.push(interceptor.fulfilled, interceptor.rejected);
    });
    // 形成 promise 链
    while (chain.length) {
        promise = promise.then(chain.shift(), chain.shift());
    }
    return promise;
};

// 这是获取 Url 的函数,省略
Axios.prototype.getUri = function getUri(config) {};

// 提供一些请求方法的别名
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
    Axios.prototype[method] = function(url, config) {
        return this.request(utils.merge(config || {}, {
            method: method,
            url: url
        }));
    };
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
    Axios.prototype[method] = function(url, data, config) {
        return this.request(utils.merge(config || {}, {
            method: method,
            url: url,
            data: data
        }));
    };
});
module.exports = Axios;

core/InterceptorManager.js文件 ,拦截器的构造函数和一些方法

// 拦截器的构造函数,handles 用于存储拦截器函数
function InterceptorManager() {
    this.handlers = [];
}
// axios.interceptors.request.use 
// axios.interceptors.response.use 
// 用于注册拦截器
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
    this.handlers.push({
        fulfilled: fulfilled,
        rejected: rejected
    });
    return this.handlers.length - 1;
};
// 根据id删除拦截器,类似 clearInterval
InterceptorManager.prototype.eject = function eject(id) {
    if (this.handlers[id]) {
        this.handlers[id] = null;
    }
};
// 遍历执行所有拦截器,传递一个回调函数 (每一个拦截器函数作为参数) 调用
// 被移除的一项是null,所以不会执行,也就达到了移除的效果
InterceptorManager.prototype.forEach = function forEach(fn) {
    utils.forEach(this.handlers, function forEachHandler(h) {
        if (h !== null) {
            fn(h);
        }
    });
};
module.exports = InterceptorManager;

core/dispatchRequest.js文件 用于处理适配器 adapter

module.exports = function dispatchRequest(config) {
    config.headers = config.headers || {};
    // 省略了部分代码,格式转换等
    utils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
        function cleanHeaderConfig(method) {
            delete config.headers[method];
        }
    );
    var adapter = config.adapter || defaults.adapter;
    // 适配器执行部分
    return adapter(config).then(function onAdapterResolution(response) {
        return response;
    }, function onAdapterRejection(reason) {
        if (!isCancel(reason)) {
            if (reason && reason.response) {
                // 格式转换
                reason.response.data = transformData(
                    reason.response.data,
                    reason.response.headers,
                    config.transformResponse
                );
            }
        }
        return Promise.reject(reason);
    });
};
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值