Axios 是一個基於 Promise 的 HTTP 客戶端,同時支持瀏覽器和 Node.js 環境。它是一個優秀的 HTTP 客戶端,被普遍地應用在大量的 Web 項目中。具體介紹可見官方文檔javascript
對於大多數應用來講,都會遇到要統一處理ajax請求的場景,爲了較好地解決這個問題,攔截器就應運而生了。
在Axios中它提供了請求攔截器和響應攔截器來分別處理請求和響應,它們的做用以下:java
接下來,本文將經過axios源碼來闡述攔截器是如何設計實現的。ios
首先如下面的代碼爲例,經過use將方法註冊到攔截器中git
// request interceptor axios.interceptors.request.use( config => { console.log('config', config); return config; }, err => Promise.reject(err), ); // response interceptor axios.interceptors.response.use(response => { console.log('response', response); return response; }); // axios/lib/core/InterceptorManager.js // 在攔截器管理類中經過use方法向任務列表中添加任務 InterceptorManager.prototype.use = function use(fulfilled, rejected) { this.handlers.push({ fulfilled: fulfilled, rejected: rejected }); return this.handlers.length - 1; };
// 先看lib/axios.js(入口文件) 中的建立實例的方法 function createInstance(defaultConfig) { var context = new Axios(defaultConfig); // REVIEW[epic=interceptors,seq=0] 在axios對象上綁定request方法,使得axios({option})這樣的方式便可調用request方法 var instance = bind(Axios.prototype.request, context); // Copy axios.prototype to instance utils.extend(instance, Axios.prototype, context); // Copy context to instance utils.extend(instance, context); return instance; } // 重點在於Axios.prototype.request Axios.prototype.request = function request(config) { // ...已省略部分代碼 // Hook up interceptors middleware // REVIEW[epic=interceptors,seq=2] dispatchRequest 爲咱們使用axios時,項目中調用的請求 var chain = [dispatchRequest, undefined]; var promise = Promise.resolve(config); // REVIEW[epic=interceptors,seq=4] 向攔截器任務列表的頭部註冊 request任務 this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { chain.unshift(interceptor.fulfilled, interceptor.rejected); }); // REVIEW[epic=interceptors,seq=5] 向攔截器任務列表的尾部註冊 response任務 this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { chain.push(interceptor.fulfilled, interceptor.rejected); }); // 經過上面的註冊方式,咱們能夠知道最後的chain數組會長成的樣子是: // [ ...requestInterceptor, dispatchRequest,undefined, ...responseInterceptor ] // 這樣就保證了攔截器執行的順序 while (chain.length) { // 由於是成對註冊的任務(fulfilled, rejected)因此執行的時候也是shift2次 promise = promise.then(chain.shift(), chain.shift()); } return promise; };
能夠看出經過從不一樣的位置向任務列表中添加任務,實現了任務的編排,達到了按requestInterceptor => Request => responseInterceptor 順序執行的目的github
任務的調度主要是看上面 request函數中的這一行ajax
var promise = Promise.resolve(config); while (chain.length) { // 由於是成對註冊的任務(fulfilled, rejected)因此執行的時候也是shift2次 promise = promise.then(chain.shift(), chain.shift()); }
能夠看出就是按註冊的順序依次執行,而且每一個任務中都須要返回config。axios
在此次的源碼閱讀時,明顯感受到,由於以前幾回的積累,讀源碼這件事開始變得沒有那麼的「困難」了。可是在寫文檔的時候如何更清晰地表達,仍是遇到了點問題。所以借鑑了下網上已有的文檔,使用了任務註冊 => 任務編排 => 任務調度,以任務爲視角來作解析的方式來闡述代碼。數組