//暗號:axios前端
處理異步在處理先後端的業務時的考慮問題,前端的Ajax = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)就是處理異步的問題,隨後Fetch和Axios進一步封裝了Ajax,使得接口更加豐富。node
axios({
url,
method,
headers,
})
axios(url, {
method,
headers,
})
axios.get(url, {
headers,
})
axios.post(url, data, {
headers,
})
axios.create(optios)
axios建立方法方法: 1. axios() -- axios方法建立, 2. axios.create()對象的create方法建立, 3.axios.request()ios
// Axios引入 (axios/index.js) module.exports = require('./lib/axios')
axios/lib/axios.js中的createInstance可以實現axios的多種建立方式ajax
function createInstance(defaultConfig) {
// 建立一個Axios的實例可是最終返回的並非這個實例 var context = new Axios(defaultConfig);
// 建立一個instance的容器,指向Axios.prototyep.request方法,並上下文指向context,最終返回。
// 咱們能用Axios() => instance() var instance = bind(Axios.prototype.request, context); // 把Axios.prototype上的方法擴展到instance對象上。
// 這樣instance又有了get、post、put等方法
// 並指向上下文context,這樣執行Axios原型鏈上的方法時,this會指向context utils.extend(instance, Axios.prototype, context); // 把context對象上的自身屬性和方法擴展到instance上
// extend方法會遍歷對象自己,不會表裏原型鏈上的方法和屬性
// instance就有了create,default, interceptors的方法和屬性
utils.extend(instance, context); return instance; } // 調用axios()方法時候,使用默認配置 var axios = createInstance(defaults); // Expose Axios class to allow class inheritance axios.Axios = Axios; // Factory for creating new instances
// 合併配置項
axios.create = function create(instanceConfig) { return createInstance(mergeConfig(axios.defaults, instanceConfig)); };
// /lib/core/Axios.js
function Axios(instanceConfig) { this.defaults = instanceConfig; this.interceptors = { request: new InterceptorManager(), response: new InterceptorManager() }; } Axios.prototype.request = function request(config) { // ...處理配置和參數合併處理,省略代碼 }; // 爲支持的請求方法提供別名 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 })); }; });
adapter是xhr.js封裝的promise對象, 它統一了不一樣環境發送請求的需求。
// default.js
// 適配器
var adapter = config.adapter || defaults.adapter; return adapter(config).then(function onAdapterResolution(response) { throwIfCancellationRequested(config); // 處理不一樣環境發出的request請求 function getDefaultAdapter() { var adapter; if (typeof XMLHttpRequest !== 'undefined') { // 處理瀏覽器的發出的請求 adapter = require('./adapters/xhr');
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') { // For node use HTTP adapter // 處理node環境的發出的請求 adapter = require('./adapters/http'); } return adapter; }
// xhr.js // 返回xhr的promise對象 module.exports = function xhrAdapter(config) { return new Promise(function dispatchXhrRequest(resolve, reject) { var request = new XMLHttpRequest(); // Send the request request.send(requestData); }); };
Axios.js中有一個攔截器InterceptorManager, 能夠簡單理解爲一個request或者response的數組,每次從隊列頭部或者尾部傳入request或者response的promise對象fullfilled和rejected函數
// InterceptorManager.js // InterceptorManager方法維護一個數組 function InterceptorManager() { this.handlers = []; } // 每次在數組尾部加入promise對象, use方法進行註冊 InterceptorManager.prototype.use = function use(fulfilled, rejected) { this.handlers.push({ fulfilled: fulfilled, rejected: rejected }); return this.handlers.length - 1; };
處理ajax的promise請求前,執行鏈chain會把攔截器數組中的promise對象請求unshift和響應push加入chain數組中, axios
// 建立一個執行鏈 [dispatchRequest, undefined], dispatchRequest是適配器ajax中封裝的promise請求 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.then(rs2, rf2).then(rs1, rf1). then(dispatchRequest, undefine).then(ps1, pf1).then(ps2, pf2)... while (chain.length) { promise = promise.then(chain.shift(), chain.shift()); } return promise; };
數組的 shift() 方法用於把數組的第一個元素從其中刪除,並返回第一個元素的值。 每次執行while循環,從chain數組裏按序取出兩項,並分別做爲promise.then方法的第一個和第二個參數 按照咱們使用InterceptorManager.prototype.use添加攔截器的規則,正好每次添加的就是咱們經過InterceptorManager.prototype.use方法添加的成功和失敗回調 經過InterceptorManager.prototype.use往攔截器數組裏添加攔截器時使用的數組的push方法, 對於請求攔截器,從攔截器數組按序讀到後是經過unshift方法往chain數組數裏添加的,又經過shift方法從chain數組裏取出的,因此得出結論:對於請求攔截器,先添加的攔截器會後執行 對於響應攔截器,從攔截器數組按序讀到後是經過push方法往chain數組裏添加的,又經過shift方法從chain數組裏取出的,因此得出結論:對於響應攔截器,添加的攔截器先執行 第一個請求攔截器的fulfilled函數會接收到promise對象初始化時傳入的config對象,而請求攔截器又規定用戶寫的fulfilled函數必須返回一個config對象,因此經過promise實現鏈式調用時,每一個請求攔截器的fulfilled函數都會接收到一個config對象 第一個響應攔截器的fulfilled函數會接受到dispatchRequest(也就是咱們的請求方法)請求到的數據(也就是response對象),而響應攔截器又規定用戶寫的fulfilled函數必須返回一個response對象,因此經過promise實現鏈式調用時,每一個響應攔截器的fulfilled函數都會接收到一個response對象 任何一個攔截器的拋出的錯誤,都會被下一個攔截器的rejected函數收到,因此dispatchRequest拋出的錯誤纔會被響應攔截器接收到。 由於axios是經過promise實現的鏈式調用,因此咱們能夠在攔截器裏進行異步操做,而攔截器的執行順序仍是會按照咱們上面說的順序執行,也就是 dispatchRequest 方法必定會等待全部的請求攔截器執行完後再開始執行,響應攔截器必定會等待 dispatchRequest 執行完後再開始執行。
// 暗號:axios
後端