自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

手寫Axios核心原理

開發(fā) 架構(gòu)
Axios天然支持Promise的性能讓其方便對異步進(jìn)行處理,同時又利用了Promise對請求進(jìn)行了攔截,使得用戶可以在請求過程中添加更多的功能,對請求的中斷能自如操作。

[[355442]]

Axios是一個基于promise的HTTP庫,它能夠自動判斷當(dāng)前環(huán)境,自由切換在瀏覽器和 node.js環(huán)境中。如果是瀏覽器,就會基于XMLHttpRequests實現(xiàn);如果是node環(huán)境,就會基于node內(nèi)置核心http模塊實現(xiàn)。同時,它還用promise處理了響應(yīng)結(jié)果,避免陷入回調(diào)地獄中去。

不僅如此,Axios還可以攔截請求和響應(yīng)、轉(zhuǎn)化請求數(shù)據(jù)和響應(yīng)數(shù)據(jù)、中斷請求、自動轉(zhuǎn)換JSON數(shù)據(jù)、客戶端支持防御XSRF等。如此眾多好用的功能,快來一起看看它是如何實現(xiàn)的吧!

1.基本使用

axios基本使用方式主要有:

  • axios(config)
  • axios.method(url,data,config)
  1. // 發(fā)送 POST 請求 
  2. axios({ 
  3.   method: 'post'
  4.   url: '/user/12345'
  5.   data: { 
  6.     username: 'Web前端嚴(yán)選'
  7.     age: 2 
  8.   } 
  9. }); 
  10. // GET請求ID參數(shù) 
  11. axios.get('/user?ID=12345'
  12.   .then(function (response) { 
  13.     console.log(response); 
  14.   }) 
  15.   .catch(function (error) { 
  16.     console.log(error); 
  17.   }); 

2.實現(xiàn)axios

從axios(config)的使用上可以看出導(dǎo)出的axios是一個方法,從axios.get()的使用上可以看出導(dǎo)出的axios原型上會有g(shù)et,post,put,delete等方法。

由分析可知,axios實際上是Axios類中的一個方法。我們可以先寫一個request方法來實現(xiàn)主要的請求功能,這樣就能使用axios(config)形式來調(diào)用了。

  1. class Axios{ 
  2.     constructor(){ 
  3.  
  4.     } 
  5.     request(config){ 
  6.         return new Promise((resolve) => { 
  7.             const {url='',data={},method='get'} = config; //解構(gòu)傳參 
  8.             const xhr = new XMLHttpRequest;     //創(chuàng)建請求對象 
  9.             xhr.open(method,url,true);  
  10.             xhr.onreadystatechange = () => { 
  11.                 if(xhr.readyState == 4 && xhr.status == 200){ 
  12.                     resolve(xhr.responseText); 
  13.                     //異步請求返回后將Promise轉(zhuǎn)為成功態(tài)并將結(jié)果導(dǎo)出 
  14.                 } 
  15.             } 
  16.             xhr.send(JSON.stringfy(data)); 
  17.         }) 
  18.     } 
  19.  
  20. function CreateAxiosFn(){ 
  21.     let axios = new Axios; 
  22.     let req = axios.request.bind(axios); 
  23.     return req; 
  24.  
  25. let axios = CreateAxiosFn(); 

然后搭建一個簡易服務(wù)端代碼,以測試請求的效果:

  1. const express = require('express'
  2.  
  3. let app = express(); 
  4.  
  5. app.all('*'function (req, res, next) { 
  6.     res.header('Access-Control-Allow-Origin''*'); 
  7.     res.header('Access-Control-Allow-Headers''Content-Type'); 
  8.     res.header('Access-Control-Allow-Methods''*'); 
  9.     res.header('Content-Type''application/json;charset=utf-8'); 
  10.     next(); 
  11. }); 
  12.  
  13. app.get('/getInfo'function(request, response){ 
  14.     let data = { 
  15.         'username':'前端嚴(yán)選'
  16.         'age':'2' 
  17.     }; 
  18.     response.json(data); 
  19. }); 
  20. app.listen(3000, function(){ 
  21.     console.log("服務(wù)器啟動"); 
  22. }); 

啟動服務(wù)后,在頁面中測試請求是否成功:

  1. <button onclick="getMsg()">點擊</button> 
  2. <script src="./axios.js"></script> 
  3. <script> 
  4.     function getMsg(){ 
  5.         axios({ 
  6.             method: 'get'
  7.             url: 'http://localhost:3000/getInfo' 
  8.         }).then(res => { 
  9.             console.log(res); 
  10.         }) 
  11.     } 
  12. </script> 

點擊按鈕后,可以看到請求成功并獲取到數(shù)據(jù)。

3.原型上的方法

接下來實現(xiàn)以axios.method()形式的方法。

通過axios.get(),axios.post(),axios.put()等方法可以看出它們都是Axios.prototype上的方法,這些方法調(diào)用內(nèi)部的request方法即可:

  1. const methodsArr = ['get','post','put','delete','head','options','patch','head']; 
  2. methodsArr.forEach(method => { 
  3.     Axios.prototype[method] = function(){ 
  4.         return this.request({ 
  5.             method: method, 
  6.             ...arguments[0] 
  7.         }) 
  8.     } 
  9. }) 

arguments的第一個參數(shù)包含url,data等信息,直接解構(gòu)它的第一個元素即可

還需要實現(xiàn)一個工具方法,用來將b方法屬性混入到a中去:

  1. const utils = { 
  2.     extend(a,b,context){ 
  3.         for(let key in b){ 
  4.             if(b.hasOwnProperty(key)){ 
  5.                 if(typeof b[key] == 'function'){ 
  6.                     a[key] = b[key].bind(context); 
  7.                 }else
  8.                     a[key] = b[key
  9.                 } 
  10.             } 
  11.         } 
  12.     } 

最終導(dǎo)出axios的request方法,使之擁有g(shù)et,post等方法

  1. function CreateAxiosFn(){ 
  2.     let axios = new Axios; 
  3.     let req = axios.request.bind(axios); 
  4.     //新增如下代碼 
  5.     utils.extend(req, Axios.prototype, axios) 
  6.     return req; 

再來測試一下post的請求:

  1. axios.post({ 
  2.     url: 'http://localhost:3000/postTest'
  3.     data: { 
  4.         a: 1, 
  5.         b: 2 
  6.     } 
  7. }).then(res => { 
  8.     console.log(res); 
  9. }) 

可以看到正確返回結(jié)果了。

4.攔截器

先來看看攔截器的使用:

  1. // 請求攔截 
  2. axios.interceptors.request.use(function (config) { 
  3.     // 在發(fā)送請求之前 
  4.     return config; 
  5.   }, function (error) { 
  6.     // 請求錯誤處理 
  7.     return Promise.reject(error); 
  8.   }); 
  9.  
  10. // 響應(yīng)攔截 
  11. axios.interceptors.response.use(function (response) { 
  12.     // 響應(yīng)數(shù)據(jù)處理 
  13.     return response; 
  14.   }, function (error) { 
  15.     // 響應(yīng)錯誤處理 
  16.     return Promise.reject(error); 
  17.   }); 

攔截器,顧名思義就是在請求之前和響應(yīng)之前,對真正要執(zhí)行的操作數(shù)據(jù)攔截住進(jìn)行一些處理。

那么如何實現(xiàn)呢,首先攔截器也是一個類,用于管理響應(yīng)和請求。

  1. class InterceptorsManage{ 
  2.     constructor(){ 
  3.         this.handlers = []; 
  4.     } 
  5.     use(onFulField,onRejected){ 
  6.         //將成功的回調(diào)和失敗的回調(diào)都存放到隊列中 
  7.         this.handlers.push({ 
  8.             onFulField, 
  9.             onRejected 
  10.         }) 
  11.     } 

axios.interceptors.response.use和axios.interceptors.request.use來定義請求和響應(yīng)的攔截方法。

這說明axios上有響應(yīng)攔截器和請求攔截器,那么如何在axios上實現(xiàn)呢:

  1. class Axios{ 
  2.     constructor(){ 
  3.         this.interceptors = { 
  4.             request: new InterceptorsManage, 
  5.             response: new InterceptorsManage 
  6.         } 
  7.     } 
  8.     //.... 

在Axios的構(gòu)造函數(shù)中新增interceptors屬性,然后定義request和response屬性用于處理請求和響應(yīng)。

執(zhí)行use方法時,會把傳入的回調(diào)函數(shù)放到handlers數(shù)組中。

這時再回看使用方式,axios.interceptors.request.use方法是綁在axios實例上的,因此同樣需要把Axios上的屬性和方法轉(zhuǎn)移到request上,將interceptors對象掛載到request方法上。

  1. function CreateAxiosFn() { 
  2.   let axios = new Axios(); 
  3.   let req = axios.request.bind(axios); 
  4.   utils.extend(req, Axios.prototype, axios) 
  5.   //新增如下代碼 
  6.   utils.extend(req, axios) 
  7.   return req; 

但是現(xiàn)在request不僅要執(zhí)行請求的發(fā)送,還要執(zhí)行攔截器中handler的回調(diào)函數(shù),因此還需要把request方法進(jìn)行一下改造:

  1. request(config){ 
  2.     //攔截器和請求的隊列 
  3.     let chain = [this.sendAjax.bind(this),undefined]; 
  4.  //請求的攔截 
  5.     this.interceptors.request.handlers.forEach(interceptor => { 
  6.         chain.unshift(interceptor.onFulField,interceptor.onRejected); 
  7.     }) 
  8.  //響應(yīng)的攔截 
  9.     this.interceptors.response.handlers.forEach(interceptor => { 
  10.         chain.push(interceptor.onFulField,interceptor.onRejected) 
  11.     }) 
  12.     let promise = Promise.resolve(config); 
  13.     while(chain.length > 0){ 
  14.         //從頭部開始依次執(zhí)行請求的攔截、真正的請求、響應(yīng)的攔截 
  15.         promise = promise.then(chain.shift(),chain.shift()); 
  16.     } 
  17.     return promise; 
  18. sendAjax(config){ 
  19.     return new Promise((resolve) => { 
  20.         const {url='',method='get',data={}} = config; 
  21.         const xhr = new XMLHttpRequest(); 
  22.         xhr.open(method,url,true); 
  23.         xhr.onreadystatechange = () => { 
  24.             if(xhr.readyState == 4 && xhr.status == 200){ 
  25.                 resolve(xhr.responseText) 
  26.             } 
  27.         } 
  28.         xhr.send(JSON.stringify(data)); 
  29.     }) 

最后執(zhí)行chain的時候是這個樣子的:

  1. chain = [ 
  2.     //請求之前成功的回調(diào)和失敗的回調(diào) 
  3.     function (config) { 
  4.         return config; 
  5.     },  
  6.     function (error) { 
  7.         return Promise.reject(error); 
  8.     } 
  9.  //真正的請求執(zhí)行 
  10.     this.sendAjax.bind(this),  
  11.     undefined, 
  12.  //請求之后響應(yīng)的成功回調(diào)和失敗回調(diào) 
  13.     function (response) { 
  14.         return response; 
  15.     },  
  16.     function (error) { 
  17.         return Promise.reject(error); 
  18.     } 

請求之前,promise執(zhí)行為:

  1. promise.then
  2.  function (config) { 
  3.         return config; 
  4.     },  
  5.     function (error) { 
  6.         return Promise.reject(error); 
  7.     } 

請求時,執(zhí)行為:

  1. promise.then
  2.  this.sendAjax.bind(this),  
  3.     undefined, 

響應(yīng)后,執(zhí)行為:

  1. promise.then
  2.  function (response) { 
  3.         return response; 
  4.     },  
  5.     function (error) { 
  6.         return Promise.reject(error); 
  7.     } 

這時我們測試一下攔截器的使用:

  1. function getMsg(){ 
  2.     axios.interceptors.request.use((config) => { 
  3.         console.log('請求攔截:',config); 
  4.         return config; 
  5.     },err => { 
  6.         return Promise.reject(err) 
  7.     }) 
  8.     axios.interceptors.response.use(response => { 
  9.         response = { 
  10.             message: '響應(yīng)數(shù)據(jù)替換'
  11.             data: response 
  12.         } 
  13.         return response 
  14.     },err => { 
  15.         console.log(err,'響應(yīng)錯誤'
  16.         return Promise.reject(err) 
  17.     }) 
  18.     axios.get({ 
  19.         url: 'http://localhost:3000/getTest'
  20.  
  21.     }).then(res => { 
  22.         console.log(res); 
  23.     }) 

可以在控制臺中看到攔截處理的打印輸出,證明攔截成功!

5.總結(jié)

Axios天然支持Promise的性能讓其方便對異步進(jìn)行處理,同時又利用了Promise對請求進(jìn)行了攔截,使得用戶可以在請求過程中添加更多的功能,對請求的中斷能自如操作。它的思想既清新樸實又不落入俗套,具有很好的借鑒意義。

看完這篇文章,你了解了Axios的核心原理了嗎?

本文轉(zhuǎn)載自微信公眾號「Web前端嚴(yán)選」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系Web前端嚴(yán)選公眾號。

 

責(zé)任編輯:武曉燕 來源: Web前端嚴(yán)選
相關(guān)推薦

2020-10-20 09:12:57

axios核心原理

2020-11-02 09:35:04

ReactHook

2021-12-14 07:43:52

Spring核心原理環(huán)境準(zhǔn)備

2020-11-24 07:48:32

React

2021-08-10 18:36:02

Express原理面試

2021-12-27 08:27:17

SpringMVC面試

2021-12-15 09:17:12

Spring依賴注入面試題

2022-08-27 13:49:36

ES7promiseresolve

2020-10-23 09:26:57

React-Redux

2021-12-12 21:01:12

CSS 技巧PurgeCss

2021-07-27 14:50:15

axiosHTTP前端

2021-12-01 06:40:32

Bind原理實現(xiàn)

2020-11-09 07:29:12

ReentrantLo源碼公平鎖

2021-07-12 09:45:36

NameServer 核心Conusmer

2020-07-03 17:20:07

Redux前端代碼

2021-11-24 10:10:32

axios前端攔截器

2021-08-02 07:57:03

注冊Nacos源碼

2020-05-21 13:25:43

Spring組件架構(gòu)

2021-04-28 10:13:58

zookeeperZNode核心原理

2021-04-21 07:52:39

核心SignalR應(yīng)用
點贊
收藏

51CTO技術(shù)棧公眾號