傳送門:ios
Axios
類的構造函數:axios
// /lib/core/Axios.js function Axios(instanceConfig) { // 默認配置 this.defaults = instanceConfig; // 攔截器 this.interceptors = { // 請求攔截器 request: new InterceptorManager(), // 響應攔截器 response: new InterceptorManager() }; }
Axios.prototype.request
方法是Axios
類原型方法中的重中之重。segmentfault
Axios.prototype.request = function request(config) { // 用於API中的 axios(config) 或 axios(url[, config]) if (typeof config === 'string') { config = arguments[1] || {}; config.url = arguments[0]; } else { config = config || {}; } // 將傳入的配置與默認配置合併 config = mergeConfig(this.defaults, config); // 設置請求方法 config.method = config.method ? config.method.toLowerCase() : 'get'; // 請求攔截 // 發送請求 // 響應攔截 }
在分析Axios.prototype.request
中攔截器與請求相關代碼以前,要先分析攔截器的原理數組
// /lib/core/InterceptorManager.js function InterceptorManager() { this.handlers = []; } // 將一個攔截器添加到handlers數組 // 對應API中的 axios.interceptors.request.use 與 axios.interceptors.resopnse.use // 返回攔截器的ID InterceptorManager.prototype.use = function use(fulfilled, rejected) { this.handlers.push({ fulfilled: fulfilled, rejected: rejected }); return this.handlers.length - 1; }; // 移除指定ID的攔截器 InterceptorManager.prototype.eject = function eject(id) { if (this.handlers[id]) { this.handlers[id] = null; } }; // 遍歷執行handlers數組中的攔截器,跳過被eject成null的項 InterceptorManager.prototype.forEach = function forEach(fn) { utils.forEach(this.handlers, function forEachHandler(h) { if (h !== null) { fn(h); } }); }; module.exports = InterceptorManager;
Axios.prototype.request = function request(config) { /* 配置相關代碼 */ // 請求鏈 chain // 首先加入發送請求的方法和 undefined var chain = [dispatchRequest, undefined]; var promise = Promise.resolve(config); // 從請求鏈的頭部將請求攔截器依次加入 this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { chain.unshift(interceptor.fulfilled, interceptor.rejected); }); // 從請求鏈的尾部將相應攔截器依次加入 this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { chain.push(interceptor.fulfilled, interceptor.rejected); }); // 遍歷請求鏈,造成 promise 鏈 while (chain.length) { promise = promise.then(chain.shift(), chain.shift()); } // 返回promise鏈 return promise; }
流程圖以下:promise
這裏尤爲應注意到請求鏈中請求攔截器的順序(handlers數組的倒序),在使用axios.interceptors.request.use
時,要留意這一點。函數
另外,Axios
類還有Axios.prototype.get
、Axios.prototype.post
、Axios.prototype.delete
等方法,實際上都是修改了Axios.prototype.request
參數config
中的method
屬性。post
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) { Axios.prototype[method] = function (url, config) { return this.request(utils.merge(config || {}, { method: method, url: url })); }; }); utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) { Axios.prototype[method] = function (url, data, config) { return this.request(utils.merge(config || {}, { method: method, url: url, data: data })); }; });
分析完Axios
類,咱們再次回到入口文件:this
// /lib/axios.js function createInstance(defaultConfig) { // 建立一個Axios類的實例,獲得一個上下文環境 // 包含defaults配置與攔截器(詳見/lib/core/Axios.js) var context = new Axios(defaultConfig); // instance是一個函數(request請求方法) // this綁定到context上下文 var instance = bind(Axios.prototype.request, context); // 將Axios.prototype的各方法綁定到instance上 // 其中this做用域爲context上下文 utils.extend(instance, Axios.prototype, context); // 將context中的屬性(defaults與攔截器)綁定到instance實例中 utils.extend(instance, context); return instance; } var axios = createInstance(defaults); /* ... */ modules.exports = axios;
如今咱們就能夠在Axios
類中找到,axios
中的defaults
、interceptors
屬性,以及axios()
、axios.get()
、axios.post()
等請求方法的由來。url