axios源碼分析——請求流程

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.jsapp

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環境。

好了,忽略了各類細節,整個流程挺清楚的了!

小白第一次分析源碼,各位湊合看吧!

關於攔截器的分析,傳送門,戳這裏

關於取消請求的分析,傳送門,戳這裏

相關文章
相關標籤/搜索