axios原始碼分析——攔截器

m_ing發表於2018-06-18

上一篇中分析了axios傳送一個簡單的get請求的完整的流程,傳送門,戳這裡

這一篇講主要來分析下axios是如何實現攔截器的,這裡只分析請求攔截器。

axios.interceptors.request.use(function(config){
    // ...
    return config;
}, function(err){
    // ...
    return Promise.reject(err)
})
複製程式碼

上面的程式碼就是定義一個請求的攔截器,需要注意的是攔截器是要在傳送請求之前定義的!

axios是一個函式我們都知道了,interceptors屬性是什麼時候定義上的呢?上一篇分析了axios上好多屬性都是從context和instance上繼承來的,所以還是按照整個思路分析,來看axios/lib/core/Axios.js檔案。

function Axios(){
    this.interceptors = {
        request = new InterceptorManager()
    }
}
複製程式碼

context是Axios的例項化物件,有interceptors物件,所以axios繼承來,也是可以訪問的到的,清楚這一點就順勢去axios/lib/core/InterceptorManager.js檔案中看InterceptorManager這個建構函式吧!

function InterceptorManager(){
    this.handlers = [];
}
InterceptorManager.prototype.use = function use(fulfilled, rejected){
    this.handlers.push({
        fulfilled : fulfilled,
        rejected : rejected
    });
    return this.handler.length - 1;
}
複製程式碼

從上面可以看到,use是定義在建構函式的原型上的,所以它的例項化物件是可以訪問的,所以到現在,axios.interceptors.request.use()我們已經解釋清楚了,就是上面的函式,進入函式看下到底做了什麼,我們定義的完成和失敗的兩個回撥函式被push到一個handlers陣列中去了,那麼這個handlers陣列到底有什麼意義呢?

目前來說好像分析被中斷了,不知道該如和進行下去,但是上一節我們在分析Axios.prototype.request方法的時候省略過一些關於攔截器的東西,去看看axios/lib/core/Axios.js

Axios.prototype.request = function(config){
    // ... 
    // 對config進行處理的程式碼還是省略掉
    var chain = [dispatchRequest, undefind];
    var promise = Promise.resolve(config);
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor){
        // 這是上一節分析省略掉的一個函式   
        // 關於這個forEach函式就是去遍歷 剛才不知道是什麼用的handlers陣列;
        chain.unshift(interceptor.fulfilled, interceptor.rejected);
        // 就是把我們定義的攔截器的回撥函式加入到chain的首部
    })
    // 關於response的也省略掉
    // 假設我們只定義了一組攔截器回撥函式,那麼現在chain應該是這樣的
    // chain = [fulfilled, rejected, dispatchRequest, undefined];
    while(chain.length){
        promise = promise.then(chain.shift(), chain.shift())
    }
    // 經過迴圈這個promise就成了
    /**
     * promise = promise.resolve(conifg)
     *      .then(interceptor.fulfilled, interceptor.rejected)
     *      .then(dispatchRequest, undefined)
     */
    return promise
}
複製程式碼

結合上一篇我們知道這個函式返回的promise是我們傳送請求之後的promise,但是在傳送請求之前先執行了fufilled(config)和rejected(err)組成的promise,這個promise執行並且resolve後才會去執行dispatchRequest(config);如果返回了reject那麼請求promise將終止,會被axios.get().catch()捕獲,所以這就是所謂的攔截。

對響應攔截器的處理也同樣是這個道理,只是將interceptor.fulfilled和interceptor.rejected回撥放在了chain陣列的後面,再此就不做分析啦!

總結一下,這個其實流程挺簡單的,就是把攔截器的回撥,放到傳送請求的promise之前,先執行。

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

相關文章