中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Axios核心原理是什么

發布時間:2021-10-26 11:19:35 來源:億速云 閱讀:201 作者:iii 欄目:web開發

這篇文章主要介紹“Axios核心原理是什么”,在日常操作中,相信很多人在Axios核心原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Axios核心原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

一、axios簡介
axios是什么?
Axios 是一個基于 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。

axios有什么特性?(不得不說面試被問到幾次)

  • 從瀏覽器中創建 XMLHttpRequests從 node.js

  • 創建 http 請求

  • 支持 Promise API

  • 攔截請求和響應轉換請求數據和響應數據

  • 取消請求

  • 自動轉換JSON 數據

  • 客戶端支持防御 XSRF

實際上,axios可以用在瀏覽器和 node.js 中是因為,它會自動判斷當前環境是什么,如果是瀏覽器,就會基于XMLHttpRequests實現axios。如果是node.js環境,就會基于node內置核心模塊http實現axios簡單來說,axios的基本原理就是

  1. axios還是屬于 XMLHttpRequest, 因此需要實現一個ajax。或者基于http 。

  2. 還需要一個promise對象來對結果進行處理。

二、基本使用方式
axios基本使用方式主要有

  1. axios(config)

  2. axios.method(url, data , config)

// index.html文件 <html> <script type="text/javascript" src="./myaxios.js"></script> <body> <button class="btn">點我發送請求</button> <script>     document.querySelector('.btn').onclick = function() {         // 分別使用以下方法調用,查看myaxios的效果         axios.post('/postAxios', {           name: '小美post'         }).then(res => {           console.log('postAxios 成功響應', res);         })          axios({           method: 'post',           url: '/getAxios'         }).then(res => {           console.log('getAxios 成功響應', res);         })     } </script> </body> </html> </html>

三、實現axios和axios.method
從axios(config)的使用上可以看出導出的axios是一個方法。從axios.method(url, data , config)的使用可以看出導出的axios上或者原型上掛有get,post等方法。

實際上導出的axios就是一個Axios類中的一個方法。

如代碼所以,核心代碼是request。我們把request導出,就可以使用axios(config)這種形式來調用axios了。

class Axios {     constructor() {      }      request(config) {         return new Promise(resolve => {             const {url = '', method = 'get', data = {}} = config;             // 發送ajax請求             const xhr = new XMLHttpRequest();             xhr.open(method, url, true);             xhr.onload = function() {                 console.log(xhr.responseText)                 resolve(xhr.responseText);             }             xhr.send(data);         })     } }

怎么導出呢?十分簡單,new Axios,獲得axios實例,再獲得實例上的request方法就好了。

// 最終導出axios的方法,即實例的request方法 function CreateAxiosFn() {     let axios = new Axios();     let req = axios.request.bind(axios);     return req; }
// 得到最后的全局變量axios let axios = CreateAxiosFn();

點擊查看此時的myAxios.js

現在axios實際上就是request方法。

你可能會很疑惑,因為我當初看源碼的時候也很疑惑:干嘛不直接寫個request方法,然后導出呢?非得這樣繞這么大的彎子。別急。后面慢慢就會講到。

現在一個簡單的axios就完成了,我們來引入myAxios.js文件并測試一下可以使用不?

簡單的搭建服務器

//server.js var express = require('express'); var app = express();  //設置允許跨域訪問該服務. app.all('*', function (req, res, next) {     res.header('Access-Control-Allow-Origin', '*');     res.header('Access-Control-Allow-Headers', 'Content-Type');     res.header('Access-Control-Allow-Methods', '*');     res.header('Content-Type', 'application/json;charset=utf-8');     next(); });  app.get('/getTest', function(request, response){     data = {         'FrontEnd':'前端',         'Sunny':'陽光'     };     response.json(data); }); var server = app.listen(5000, function(){     console.log("服務器啟動"); });
//index.html <script type="text/javascript" src="./myAxios.js"></script>  <body> <button class="btn">點我發送請求</button> <script>     document.querySelector('.btn').onclick = function() {         // 分別使用以下方法調用,查看myaxios的效果         axios({           method: 'get',           url: 'http://localhost:5000/getTest'         }).then(res => {           console.log('getAxios 成功響應', res);         })     } </script> </body>

點擊按鈕,看看是否能成功獲得數據。

發現確實成功。

可喜可賀

現在我們來實現下axios.method()的形式。

思路:我們可以再Axios.prototype添加這些方法。而這些方法內部調用request方法即可,如代碼所示:

// 定義get,post...方法,掛在到Axios原型上 const methodsArr = ['get', 'delete', 'head', 'options', 'put', 'patch', 'post']; methodsArr.forEach(met => {     Axios.prototype[met] = function() {         console.log('執行'+met+'方法');         // 處理單個方法         if (['get', 'delete', 'head', 'options'].includes(met)) { // 2個參數(url[, config])             return this.request({                 method: met,                 url: arguments[0],                 ...arguments[1] || {}             })         } else { // 3個參數(url[,data[,config]])             return this.request({                 method: met,                 url: arguments[0],                 data: arguments[1] || {},                 ...arguments[2] || {}             })         }      } })

我們通過遍歷methodsArr數組,依次在Axios.prototype添加對應的方法,注意的是'get', 'delete', 'head', 'options'這些方法只接受兩個參數。而其他的可接受三個參數,想一下也知道,get不把參數放body的。

但是,你有沒有發現,我們只是在Axios的prototype上添加對應的方法,我們導出去的可是request方法啊,那怎么辦?簡單,把Axios.prototype上的方法搬運到request上即可。

我們先來實現一個工具方法,實現將b的方法混入a;

const utils = {   extend(a,b, context) {     for(let key in b) {       if (b.hasOwnProperty(key)) {         if (typeof b[key] === 'function') {           a[key] = b[key].bind(context);         } else {           a[key] = b[key]         }       }            }   } }

然后我們就可以利用這個方法將Axios.prototype上的方法搬運到request上啦。

我們修改一下之前的CreateAxiosFn方法即可

function CreateAxiosFn() {   let axios = new Axios();      let req = axios.request.bind(axios);   增加代碼   utils.extend(req, Axios.prototype, axios)      return req; }

點擊查看此時的myAxios.js

現在來測試一下能不能使用axios.get()這種形式調用axios。

<body> <button class="btn">點我發送請求</button> <script>     document.querySelector('.btn').onclick = function() {          axios.get('http://localhost:5000/getTest')             .then(res => {                  console.log('getAxios 成功響應', res);             })      } </script> </body>

又是意料之中成功。再完成下一個功能之前,先給上目前myAxios.js的完整代碼

class Axios {     constructor() {      }      request(config) {         return new Promise(resolve => {             const {url = '', method = 'get', data = {}} = config;             // 發送ajax請求             console.log(config);             const xhr = new XMLHttpRequest();             xhr.open(method, url, true);             xhr.onload = function() {                 console.log(xhr.responseText)                 resolve(xhr.responseText);             }             xhr.send(data);         })     } }  // 定義get,post...方法,掛在到Axios原型上 const methodsArr = ['get', 'delete', 'head', 'options', 'put', 'patch', 'post']; methodsArr.forEach(met => {     Axios.prototype[met] = function() {         console.log('執行'+met+'方法');         // 處理單個方法         if (['get', 'delete', 'head', 'options'].includes(met)) { // 2個參數(url[, config])             return this.request({                 method: met,                 url: arguments[0],                 ...arguments[1] || {}             })         } else { // 3個參數(url[,data[,config]])             return this.request({                 method: met,                 url: arguments[0],                 data: arguments[1] || {},                 ...arguments[2] || {}             })         }      } })   // 工具方法,實現b的方法或屬性混入a; // 方法也要混入進去 const utils = {   extend(a,b, context) {     for(let key in b) {       if (b.hasOwnProperty(key)) {         if (typeof b[key] === 'function') {           a[key] = b[key].bind(context);         } else {           a[key] = b[key]         }       }            }   } }   // 最終導出axios的方法-》即實例的request方法 function CreateAxiosFn() {     let axios = new Axios();      let req = axios.request.bind(axios);     // 混入方法, 處理axios的request方法,使之擁有get,post...方法     utils.extend(req, Axios.prototype, axios)     return req; }  // 得到最后的全局變量axios let axios = CreateAxiosFn();

四、請求和響應攔截器
我們先看下攔截器的使用

// 添加請求攔截器 axios.interceptors.request.use(function (config) {     // 在發送請求之前做些什么     return config;   }, function (error) {     // 對請求錯誤做些什么     return Promise.reject(error);   });  // 添加響應攔截器 axios.interceptors.response.use(function (response) {     // 對響應數據做點什么     return response;   }, function (error) {     // 對響應錯誤做點什么     return Promise.reject(error);   });

攔截器是什么意思呢?其實就是在我們發送一個請求的時候會先執行請求攔截器的代碼,然后再真正地執行我們發送的請求,這個過程會對config,也就是我們發送請求時傳送的參數進行一些操作。

而當接收響應的時候,會先執行響應攔截器的代碼,然后再把響應的數據返回來,這個過程會對response,也就是響應的數據進行一系列操作。

怎么實現呢?需要明確的是攔截器也是一個類,管理響應和請求。因此我們先實現攔截器

class InterceptorsManage {   constructor() {     this.handlers = [];   }    use(fullfield, rejected) {     this.handlers.push({       fullfield,       rejected     })   } }

我們是用這個語句axios.interceptors.response.use和axios.interceptors.request.use,來觸發攔截器執行use方法的。

說明axios上有一個響應攔截器和一個請求攔截器。那怎么實現Axios呢?看代碼

class Axios {     constructor() {         新增代碼         this.interceptors = {             request: new InterceptorsManage,             response: new InterceptorsManage         }     }      request(config) {         return new Promise(resolve => {             const {url = '', method = 'get', data = {}} = config;             // 發送ajax請求             console.log(config);             const xhr = new XMLHttpRequest();             xhr.open(method, url, true);             xhr.onload = function() {                 console.log(xhr.responseText)                 resolve(xhr.responseText);             };             xhr.send(data);         })     } }

可見,axios實例上有一個對象interceptors。這個對象有兩個攔截器,一個用來處理請求,一個用來處理響應。

所以,我們執行語句axios.interceptors.response.use和axios.interceptors.request.use的時候,實現獲取axios實例上的interceptors對象,然后再獲取response或request攔截器,再執行對應的攔截器的use方法。

而執行use方法,會把我們傳入的回調函數push到攔截器的handlers數組里。

到這里你有沒有發現一個問題。這個interceptors對象是Axios上的啊,我們導出的是request方法啊(欸?好熟悉的問題,上面提到過哈哈哈~~~額)。處理方法跟上面處理的方式一樣,都是把Axios上的方法和屬性搬到request過去,也就是遍歷Axios實例上的方法,得以將interceptors對象掛載到request上。

所以只要更改下CreateAxiosFn方法即可。

function CreateAxiosFn() {   let axios = new Axios();      let req = axios.request.bind(axios);   // 混入方法, 處理axios的request方法,使之擁有get,post...方法   utils.extend(req, Axios.prototype, axios)   新增代碼   utils.extend(req, axios)   return req; }

好了,現在request也有了interceptors對象,那么什么時候拿interceptors對象中的handler之前保存的回調函數出來執行。

沒錯,就是我們發送請求的時候,會先獲取request攔截器的handlers的方法來執行。再執行我們發送的請求,然后獲取response攔截器的handlers的方法來執行。

因此,我們要修改之前所寫的request方法 之前是這樣的。

request(config) {     return new Promise(resolve => {         const {url = '', method = 'get', data = {}} = config;         // 發送ajax請求         console.log(config);         const xhr = new XMLHttpRequest();         xhr.open(method, url, true);         xhr.onload = function() {             console.log(xhr.responseText)             resolve(xhr.responseText);         };         xhr.send(data);     }) }

但是現在request里不僅要執行發送ajax請求,還要執行攔截器handlers中的回調函數。所以,最好下就是將執行ajax的請求封裝成一個方法

request(config) {     this.sendAjax(config) } sendAjax(config){     return new Promise(resolve => {         const {url = '', method = 'get', data = {}} = config;         // 發送ajax請求         console.log(config);         const xhr = new XMLHttpRequest();         xhr.open(method, url, true);         xhr.onload = function() {             console.log(xhr.responseText)             resolve(xhr.responseText);         };         xhr.send(data);     }) }

好了,現在我們要獲得handlers中的回調

request(config) {     // 攔截器和請求組裝隊列     let chain = [this.sendAjax.bind(this), undefined] // 成對出現的,失敗回調暫時不處理      // 請求攔截     this.interceptors.request.handlers.forEach(interceptor => {         chain.unshift(interceptor.fullfield, interceptor.rejected)     })      // 響應攔截     this.interceptors.response.handlers.forEach(interceptor => {         chain.push(interceptor.fullfield, interceptor.rejected)     })      // 執行隊列,每次執行一對,并給promise賦最新的值     let promise = Promise.resolve(config);     while(chain.length > 0) {         promise = promise.then(chain.shift(), chain.shift())     }     return promise; }

我們先把sendAjax請求和undefined放進了chain數組里,再把請求攔截器的handlers的成對回調放到chain數組頭部。再把響應攔截器的handlers的承兌回調反倒chain數組的尾部。

然后再 逐漸取數 chain數組的成對回調執行。

promise = promise.then(chain.shift(), chain.shift())

這一句,實際上就是不斷將config從上一個promise傳遞到下一個promise,期間可能回調config做出一些修改。什么意思?我們結合一個例子來講解一下

首先攔截器是這樣使用的

// 添加請求攔截器  axios.interceptors.request.use(function (config) {     // 在發送請求之前做些什么     return config;   }, function (error) {     // 對請求錯誤做些什么     return Promise.reject(error);   });  // 添加響應攔截器 axios.interceptors.response.use(function (response) {     // 對響應數據做點什么     return response;   }, function (error) {     // 對響應錯誤做點什么     return Promise.reject(error);   });

然后執行request的時候。chain數組的數據是這樣的

chain = [   function (config) {     // 在發送請求之前做些什么     return config;   },       function (error) {     // 對請求錯誤做些什么     return Promise.reject(error);   }   this.sendAjax.bind(this),       undefined,      function (response) {     // 對響應數據做點什么     return response;   },    function (error) {     // 對響應錯誤做點什么     return Promise.reject(error);   } ]

首先
執行第一次promise.then(chain.shift(), chain.shift()),即

promise.then(   function (config) {     // 在發送請求之前做些什么     return config;   },       function (error) {     // 對請求錯誤做些什么     return Promise.reject(error);   } )

一般情況,promise是resolved狀態,是執行成功回調的,也就是執行

function (config) {     // 在發送請求之前做些什么     return config;   },

promise.then是要返回一個新的promise對象的。為了區分,在這里,我會把這個新的promise對象叫做第一個新的promise對象 這個第一個新的promise對象會把

function (config) {     // 在發送請求之前做些什么     return config;   },

的執行結果傳入resolve函數中

resolve(config)

使得這個返回的第一個新的promise對象的狀態為resovled,而且第一個新的promise對象的data為config。

這里需要對Promise的原理足夠理解。所以我前一篇文章寫的是手寫Promise核心原理,再也不怕面試官問我Promise原理,你可以去看看

接下來,再執行

promise.then(   sendAjax(config)   ,   undefined )

注意:這里的promise是 上面提到的第一個新的promise對象。

而promise.then這個的執行又會返回第二個新的promise對象。

因為這里promise.then中的promise也就是第一個新的promise對象的狀態是resolved的,所以會執行sendAjax()。而且會取出第一個新的promise對象的data 作為config轉入sendAjax()。

當sendAjax執行完,就會返回一個response。這個response就會保存在第二個新的promise對象的data中。

接下來,再執行

promise.then(   function (response) {     // 對響應數據做點什么     return response;   },    function (error) {     // 對響應錯誤做點什么     return Promise.reject(error);   } )

同樣,會把第二個新的promise對象的data取出來作為response參數傳入

function (response) {     // 對響應數據做點什么     return response;   },

飯后返回一個promise對象,這個promise對象的data保存了這個函數的執行結果,也就是返回值response。

然后通過return promise;

把這個promise返回了。咦?是怎么取出promise的data的。我們看看我們平常事怎么獲得響應數據的

axios.get('http://localhost:5000/getTest')     .then(res => {          console.log('getAxios 成功響應', res);     })

在then里接收響應數據。所以原理跟上面一樣,將返回的promise的data作為res參數了。

現在看看我們的myAxios完整代碼吧,好有個全面的了解

class InterceptorsManage {     constructor() {         this.handlers = [];     }      use(fullfield, rejected) {         this.handlers.push({             fullfield,             rejected         })     } }  class Axios {     constructor() {         this.interceptors = {             request: new InterceptorsManage,             response: new InterceptorsManage         }     }      request(config) {         // 攔截器和請求組裝隊列         let chain = [this.sendAjax.bind(this), undefined] // 成對出現的,失敗回調暫時不處理          // 請求攔截         this.interceptors.request.handlers.forEach(interceptor => {             chain.unshift(interceptor.fullfield, interceptor.rejected)         })          // 響應攔截         this.interceptors.response.handlers.forEach(interceptor => {             chain.push(interceptor.fullfield, interceptor.rejected)         })          // 執行隊列,每次執行一對,并給promise賦最新的值         let promise = Promise.resolve(config);         while(chain.length > 0) {             promise = promise.then(chain.shift(), chain.shift())         }         return promise;     }     sendAjax(){         return new Promise(resolve => {             const {url = '', method = 'get', data = {}} = config;             // 發送ajax請求             console.log(config);             const xhr = new XMLHttpRequest();             xhr.open(method, url, true);             xhr.onload = function() {                 console.log(xhr.responseText)                 resolve(xhr.responseText);             };             xhr.send(data);         })     } }  // 定義get,post...方法,掛在到Axios原型上 const methodsArr = ['get', 'delete', 'head', 'options', 'put', 'patch', 'post']; methodsArr.forEach(met => {     Axios.prototype[met] = function() {         console.log('執行'+met+'方法');         // 處理單個方法         if (['get', 'delete', 'head', 'options'].includes(met)) { // 2個參數(url[, config])             return this.request({                 method: met,                 url: arguments[0],                 ...arguments[1] || {}             })         } else { // 3個參數(url[,data[,config]])             return this.request({                 method: met,                 url: arguments[0],                 data: arguments[1] || {},                 ...arguments[2] || {}             })         }      } })   // 工具方法,實現b的方法混入a; // 方法也要混入進去 const utils = {     extend(a,b, context) {         for(let key in b) {             if (b.hasOwnProperty(key)) {                 if (typeof b[key] === 'function') {                     a[key] = b[key].bind(context);                 } else {                     a[key] = b[key]                 }             }          }     } }   // 最終導出axios的方法-》即實例的request方法 function CreateAxiosFn() {     let axios = new Axios();      let req = axios.request.bind(axios);     // 混入方法, 處理axios的request方法,使之擁有get,post...方法     utils.extend(req, Axios.prototype, axios)     return req; }  // 得到最后的全局變量axios let axios = CreateAxiosFn();

來測試下攔截器功能是否正常

<script type="text/javascript" src="./myAxios.js"></script>  <body> <button class="btn">點我發送請求</button> <script>     // 添加請求攔截器     axios.interceptors.request.use(function (config) {         // 在發送請求之前做些什么         config.method = "get";         console.log("被我請求攔截器攔截了,哈哈:",config);         return config;     }, function (error) {         // 對請求錯誤做些什么         return Promise.reject(error);     });      // 添加響應攔截器     axios.interceptors.response.use(function (response) {         // 對響應數據做點什么         console.log("被我響應攔截攔截了,哈哈 ");         response = {message:"響應數據被我替換了,啊哈哈哈"}         return response;     }, function (error) {         // 對響應錯誤做點什么         console.log("錯了嗎");         return Promise.reject(error);     });     document.querySelector('.btn').onclick = function() {         // 分別使用以下方法調用,查看myaxios的效果         axios({           url: 'http://localhost:5000/getTest'         }).then(res => {           console.log('response', res);         })     } </script> </body>

攔截成功!!!!!

到此,關于“Axios核心原理是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

金秀| 当阳市| 黄大仙区| 漠河县| 封丘县| 天等县| 佛冈县| 湛江市| 琼中| 奉节县| 上蔡县| 绥芬河市| 卓资县| 乌兰察布市| 宽城| 莱芜市| 连云港市| 辽阳市| 离岛区| 淮阳县| 图木舒克市| 百色市| 柳河县| 桂平市| 呼图壁县| 白城市| 平凉市| 抚松县| 长汀县| 合江县| 镇雄县| 景泰县| 饶河县| 淮安市| 龙江县| 满城县| 调兵山市| 安丘市| 安岳县| 华蓥市| 恩施市|