axios就不在里介绍了,直接步入正题,先从一个最基本的get请求来分析下源码。
axios.get('/get?name=xmz') .then((response)=>{ console.log('response', response) }) .catch((error)=>{ console.log('error', error) }) |
先从axios这个对象看,暂且认为它是一个普通的对象,加载axios文件后,直接就可以使用,所以就直接去文件里找它去~~~
找到axios/lib/axios.js就直接看到了var axios躺在哪里。
var axios = createInstance(defaults);
先不管defaults就当是一个默认的对象,向上看就看到了createInstance方法
function createInstance(defaultConfig){ var context = new Axios(defaultConfig); //new Axios()这么说context 是一个对象了 var instance = bind(Axios.prototype.request, context); //bind()要对这个对象干什么??? //...下面的就先不看了 return instance; } |
再扯远点,看看bind方法到底对context干什么了?bind定义在axios/lib/helps/bind.js这个目录下
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) } } |
bind返回一个函数wrap,暂且不看里面得话,我们就可以知道instance是一个函数,那么当instance执行的时候,其实就是执行Axios.proptotype.request,this指向context,说白了bind就是改变了this指向嘛,createInstance函数返回就是这个instance,所以axios就是instance,就是一个函数。
既然axios是一个函数,那么这个函数的get属性在哪定义的呢?然后我就在整个axios/lib文件夹下简单粗暴地搜了下axios.get,然而并没有找到~~~
找了半天没找到啊!!抓狂!!但是在来回翻源码的时候看到Axios.prototype上有get属性,但是axios却不是Axios的实例化对象啊,怎么办?
此时发现在var axios之后,axios马上就已经有get属性了(写了个for in 循环偷偷看了下),那么就顺着向上找把,还是找到了createInstance方法
function createInstance(){ //... //刚才有两行省略掉没看 好后悔! //看到extend 好激动 utils.extend(instance, Axios.prototype, context); utils.extend(instance, context) return instance } |
这下知道了,axios的get属性原来是从Axios.prototype上继承来的,那就去看看utils.entend是怎么工作的吧!进入了axios/lib/util.js文件。
function extend(a, b, thisArg){ // extend就是把b的属性都复制个a forEach(b, function(value, key){ //如果属性的值是一个方法的话,就改变this的指向到thisArg再复制给a if(thisArg && typeof value == 'function'){ a[key] = bind(val, thisArg) }else{ a[key] = value; } }) return a } |
axios继承了Axios.prototype和context的所有的属性,属性值是方法的话,里面的this都是指向context的。
这回就可以去看Axios.prototype.get了,不去搜了,我看到它不是直接定义的了!哈哈哈!在axios/lib/core/Axios.js里
utils.forEach(['delete', 'get', 'head', 'option'], function(method){ Axios.proptotype[method] = function(url, config){ // 先不去看util.merge了,我猜也就是把config 和 后面的对象进行下合并 return this.request(util.merge(config||{}, { method: method, url: url })) } }) |
Axios.prototype.get()其实去执行的是Axios.prototype.request(),还在这个文件里,向上看
Axios.prototype.request = function request(config){ // ... // 开始就对config进行判断,合并默认配置 var chain = [dispatchRequest, undefined] // dispatchRequest是什么一会再说 var promise = Promise.resolve(config) // Promise.resolve一个对象,promise就是一个立即resolve的Promise对象 // ... // 关于interceptors拦截器的东西先不看了 while(chain.length){ promise = promise.then(chain.shift(), chain.shift()) } return promise } |
返回的是一个promise这就和axios.get('/get?name=xmz').then().catch()对上了。暂且不考虑拦截器,经过这个while循环其实就是去执行了dispatchRequest(config),那么就去axios/lib/core/dispatchRequest.js看下吧
function dispatchRequest(config){ // ... // 开始就对config的 baseUrl, data, headers进行处理 var adapter = config.adapter || defaults.adapter; // 这个adapter是什么?一路以来并没有关注啊? // 执行adapter是一个Promise对象,resolve的函数的参数还是response // adpater肯定是去发送请求了啊 return adapter(config).then(function(response){ // ... return response }, function(reason){ // ... return Promise.reject(reason) }) } |
既然config.adapter没看见,就去axios/lib/default.js看defaults.adapter吧
var defaults.adapter = getDefaultAdapter(); function getDefaultAdapter(){ var adapter; if(typeof XMLHttpRequest !== 'undefined'){ // 浏览器环境 adapter = require('./adapter/xhr'); }else if(typeof process !== 'undefined'){ // node环境 adapter = require('./adapter/http'); } return adapter; } |
adapter是区分浏览器和node环境的,那么我们就去axios/lib/adapter/xhr.js看下浏览器环境的吧,就是封装了一个promise进行ajax请求服务器,就先不在这里看了。
至此回过头来再看开始那个get请求,axios.get继承于Axios.prototype.get,其实就是去执行Axios.prototype.request,返回一个promsie对象,所以可以使用then和catch接收返回值和处理错误。进行ajax请求的主要函数就是adapter,adapter区分了一下浏览器和node环境。
好了,忽略了各种细节,整个流程挺清楚的了!
小白第一次分析源码,各位凑合看吧!
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。