初識Axios源碼

//暗號:axios前端

處理異步在處理先後端的業務時的考慮問題,前端的Ajax = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)就是處理異步的問題,隨後Fetch和Axios進一步封裝了Ajax,使得接口更加豐富。node

1. Axios的建立

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)); };

 

Axios模塊是axios的核心,一個Axios實例對應一個axios對象,其餘方法都是對Axios內容的擴展
Axios構造函數的核心方法是request方法,各類axios的調用方式最終都是經過request方法發請求的。
調用axios等同於Axios.prototype.request
調用axios.reuqest等同於Axios.prototype.request
調用axios.get等同於Axios.ptototype.get
// /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 })); }; });

 

2. 統一發送請求的適配器adapter

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);
  });
};

 

 

3. InterceptoManager 攔截器

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;
};

 

4. 執行鏈處理攔截器的請求和響應

處理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; };

 

5.  執行鏈處理請求和響應的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後端

相關文章
相關標籤/搜索