axios就不在裏介紹了,直接步入正題,先從一個最基本的get請求來分析下源碼。javascript
axios.get('/get?name=xmz')
.then((response)=>{
console.log('response', response)
})
.catch((error)=>{
console.log('error', error)
})
複製代碼
先從axios這個對象看,暫且認爲它是一個普通的對象,加載axios文件後,直接就可使用,因此就直接去文件裏找它去~~~java
找到axios/lib/axios.js
就直接看到了var axios躺在哪裏。node
var axios = createInstance(defaults);
複製代碼
先無論defaults就當是一個默認的對象,向上看就看到了createInstance方法ios
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
這個目錄下ajax
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
既然axios是一個函數,那麼這個函數的get屬性在哪定義的呢?而後我就在整個axios/lib
文件夾下簡單粗暴地搜了下axios.get,然而並無找到~~~ 找了半天沒找到啊!!抓狂!!可是在來回翻源碼的時候看到Axios.prototype上有get屬性,可是axios卻不是Axios的實例化對象啊,怎麼辦?promise
此時發如今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
裏app
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環境。
好了,忽略了各類細節,整個流程挺清楚的了!
小白第一次分析源碼,各位湊合看吧!
關於攔截器的分析,傳送門,戳這裏。
關於取消請求的分析,傳送門,戳這裏。