JavaScript封裝axios的實(shí)現(xiàn)詳解
摘要
在vue中,我們調(diào)用接口使用的都是axios,使用之前我們也會(huì)進(jìn)行一定的封裝,然后再進(jìn)行使用。
在這里,我們主要說一下axios的實(shí)現(xiàn)原理,以及如何使用原生的js來自己封裝出一個(gè)axios。
這里實(shí)現(xiàn)出幾個(gè)主要的方法,包括post請(qǐng)求方法,create配置方法,以及攔截器的方法。
1.post方法
在我們寫方法之前,肯定是要先自己寫一個(gè)類出來,里面的內(nèi)容先不用寫。
然后再在類的下面寫出post的方法:
function iaxios () { } iaxios.prototype.post = function (url, data){ }
OK,現(xiàn)在我們來實(shí)現(xiàn)這個(gè)方法。
如果我們想用原生的js來實(shí)現(xiàn)post請(qǐng)求,我們應(yīng)該這樣做:
var xhr = new XMLHttpRequest(); xhr.open('post', url, true); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if ((xhr.status == 200 || xhr.status == 304)) { resolve(xhr.responseText) } else { reject(xhr.responseText) } } }; xhr.send(data)
但是我們直接把這段代碼放進(jìn)去的話,會(huì)有一點(diǎn)問題:
1.官方的axios返回的是一個(gè)promise對(duì)象
2.官方的axios.post方法傳的data參數(shù)是一個(gè)對(duì)象,原生的是一個(gè)字符串
所以為了解決第一個(gè)問題,我們可以在方法內(nèi)返回一個(gè)promise對(duì)象,而第二個(gè)問題可以使用JSON.stringfy()這個(gè)方法解決。
iaxios.prototype.post = function (url, data) { //返回promise對(duì)象 return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); xhr.open('post', url, true); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if ((xhr.status == 200 || xhr.status == 304)) { resolve(xhr.responseText) } else { reject(xhr.responseText) } } }; xhr.send(JSON.stringify(data)) }) }
這樣我們就實(shí)現(xiàn)了post的這個(gè)方法了。
而對(duì)get方法這里就不再寫一遍了(寫的時(shí)候主要注意參數(shù)的問題就可以了)。
2.create方法
首先我們知道,axios的create方法主要是對(duì)請(qǐng)求頭等參數(shù)的配置,而這個(gè)方法同樣也會(huì)返回一個(gè)axios的實(shí)例,這個(gè)實(shí)例可以繼續(xù)使用post等方法。
所以我們首先想到的是,這個(gè)方法應(yīng)該返回一個(gè)實(shí)例對(duì)象,而這個(gè)實(shí)例對(duì)象下的屬性會(huì)根據(jù)傳進(jìn)來的對(duì)象設(shè)置。
這里面我只列舉兩個(gè)屬性:
iaxios.prototype.create = function (obj) { var emaxios = new iaxios() emaxios.headers = obj.headers; emaxios.baseUrl = obj.baseUrl; return emaxios; }
但是我們調(diào)用完這個(gè)create方法后,我們已經(jīng)有了一些配置,如果再調(diào)用post等方法,我們應(yīng)該是攜帶著這些參數(shù)去調(diào)用psot方法,所以在post方法內(nèi)我們也要修改一下。
我們首先寫一個(gè)配置請(qǐng)求頭的方法:
function setHeader (xhr, headers) { for (var i in headers) { xhr.setRequestHeader(i, headers[i]); } }
然后在post方法內(nèi),在ajax請(qǐng)求發(fā)送之前調(diào)用這個(gè)方法就可以了:
setHeader(xhr, this.headers);
3.攔截器
在axios中,攔截器分兩種,分別是請(qǐng)求攔截和響應(yīng)攔截。
二者的作用也是相差不多的,一個(gè)是希望在請(qǐng)求之前做什么,一個(gè)是希望在請(qǐng)求之后做什么。
我們先來寫一下請(qǐng)求攔截(這里面不考慮use):
我們先想一下,interceptors一定是一個(gè)對(duì)象,并且下面有兩個(gè)屬性,分別是request和response。
那么我們就在類里面寫一下:
function iaxios () { this.interceptors = { request (cb) { }, response (aa) { }, } }
如果我們想在外邊調(diào)用這個(gè)方法,會(huì)將一個(gè)回調(diào)函數(shù)傳進(jìn)來,
所以在我們這里我們需要把這個(gè)回調(diào)函數(shù)保存下來(考慮到有多個(gè)攔截器,所以我們采用數(shù)組保存)。
同時(shí)我們也要寫一個(gè)data用于存放請(qǐng)求時(shí)的數(shù)據(jù)(因?yàn)樵谡?qǐng)求攔截器的回調(diào)函數(shù)中,有一個(gè)config參數(shù),它包含著請(qǐng)求的數(shù)據(jù))
function iaxios () { //保存攔截器中的回調(diào)函數(shù) this.saveRequest = [] this.saveResponse = [] //保存請(qǐng)求的數(shù)據(jù) this.data = {}; let _this = this; this.interceptors = { request (cb) { _this.saveRequest.push(cb) }, response (aa) { _this.saveResponse.push(aa) }, } }
現(xiàn)在攔截器的方法已經(jīng)寫好了,我們應(yīng)該在什么時(shí)候調(diào)用呢?
請(qǐng)求攔截一定是在請(qǐng)求發(fā)送之前進(jìn)行調(diào)用,我們拿post來舉例子:
iaxios.prototype.post = function (url, data) { this.data = data; let _this = this; // this.saveRequest && this.saveRequest(this) //請(qǐng)求之前調(diào)用請(qǐng)求攔截的回調(diào)函數(shù) if (this.saveRequest) { this.saveRequest.forEach(fn => { fn(this) }) }
我們只需要在請(qǐng)求之前,把想要傳遞的數(shù)據(jù)copy下來(用于當(dāng)作參數(shù))。
然后循環(huán)調(diào)用我們保存下來的方法(其實(shí)就是調(diào)用的時(shí)候傳遞回調(diào)函數(shù))
這樣就能實(shí)現(xiàn)請(qǐng)求攔截了。
那么響應(yīng)攔截一定是在返回響應(yīng)數(shù)據(jù)之前調(diào)用了:
if ((xhr.status == 200 || xhr.status == 304)) { //用來保存返回的數(shù)據(jù) let newRespose = new Object; newRespose.data = JSON.parse(xhr.responseText); //在返回?cái)?shù)據(jù)之前調(diào)用相應(yīng)攔截器的回調(diào)函數(shù) if (_this.saveResponse) { _this.saveResponse.forEach(fn => { fn(newRespose) }) } resolve(newRespose.data)
這里面我們創(chuàng)建的newRespose也是為了當(dāng)作參數(shù)傳遞到響應(yīng)攔截的方法里面。
這樣的話響應(yīng)攔截器的實(shí)現(xiàn)也完成了。
4.代碼
最后再把整體的代碼復(fù)制一份:
// const { resolve, reject } = require("core-js/fn/promise") function iaxios () { //保存攔截器中的回調(diào)函數(shù) this.saveRequest = [] this.saveResponse = [] //保存請(qǐng)求的數(shù)據(jù) this.data = {}; let _this = this; this.interceptors = { request (cb) { _this.saveRequest.push(cb) }, response (aa) { _this.saveResponse.push(aa) }, } } iaxios.prototype.post = function (url, data) { this.data = data; let _this = this; // this.saveRequest && this.saveRequest(this) //請(qǐng)求之前調(diào)用請(qǐng)求攔截的回調(diào)函數(shù) if (this.saveRequest) { this.saveRequest.forEach(fn => { fn(this) }) } //返回promise對(duì)象 return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); xhr.open('post', url, true); //設(shè)置請(qǐng)求頭的配置 setHeader(xhr, this.headers); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if ((xhr.status == 200 || xhr.status == 304)) { //用來保存返回的數(shù)據(jù) let newRespose = new Object; newRespose.data = JSON.parse(xhr.responseText); // _this.saveResponse && _this.saveResponse(newRespose) //在返回?cái)?shù)據(jù)之前調(diào)用相應(yīng)攔截器的回調(diào)函數(shù) if (_this.saveResponse) { _this.saveResponse.forEach(fn => { fn(newRespose) }) } resolve(newRespose.data) } else { reject(xhr.responseText) } } }; xhr.send(JSON.stringify(data)) }) } iaxios.prototype.get = function (url) { let _this = this; // this.saveRequest && this.saveRequest(this) //請(qǐng)求之前調(diào)用請(qǐng)求攔截的回調(diào)函數(shù) if (this.saveRequest) { this.saveRequest.forEach(fn => { fn(this) }) } //返回promise對(duì)象 return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); xhr.open('get', url, true); //設(shè)置請(qǐng)求頭的配置 setHeader(xhr, this.headers); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if ((xhr.status == 200 || xhr.status == 304)) { //用來保存返回的數(shù)據(jù) let newRespose = new Object; newRespose.data = JSON.parse(xhr.responseText); // _this.saveResponse && _this.saveResponse(newRespose) //在返回?cái)?shù)據(jù)之前調(diào)用相應(yīng)攔截器的回調(diào)函數(shù) if (_this.saveResponse) { _this.saveResponse.forEach(fn => { fn(newRespose) }) } resolve(newRespose.data) } else { reject(xhr.responseText) } } }; xhr.send() }) } //返回一個(gè)新的實(shí)例并且復(fù)制obj的屬性 iaxios.prototype.create = function (obj) { var emaxios = new iaxios() emaxios.headers = obj.headers; emaxios.baseUrl = obj.baseUrl; return emaxios; } //設(shè)置請(qǐng)求頭的方法 function setHeader (xhr, headers) { for (var i in headers) { xhr.setRequestHeader(i, headers[i]); } } var taxios = new iaxios(); export { taxios }
到此這篇關(guān)于JavaScript封裝axios的實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)JS封裝axios內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
bootstrap實(shí)現(xiàn)tab選項(xiàng)卡切換
這篇文章主要為大家詳細(xì)介紹了bootstrap實(shí)現(xiàn)tab選項(xiàng)卡切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08JavaScript實(shí)現(xiàn)隱藏省略文字效果的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)隱藏省略文字效果的方法,涉及javascript基于事件響應(yīng)實(shí)現(xiàn)頁面字符串元素的獲取、截取、設(shè)置等相關(guān)操作技巧,需要的朋友可以參考下2017-04-04js實(shí)現(xiàn)顯示手機(jī)號(hào)碼效果
本文主要介紹了js實(shí)現(xiàn)顯示手機(jī)號(hào)碼效果的實(shí)例,具有很好的參考價(jià)值。下面跟著小編一起來看下吧2017-03-03Nuxt.js中PC與移動(dòng)端間自動(dòng)識(shí)別跳轉(zhuǎn)
本文主要介紹了Nuxt.js中PC與移動(dòng)端間自動(dòng)識(shí)別跳轉(zhuǎn),文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03JavaScript設(shè)置彈出式獨(dú)立窗口頁面和window的方法舉例詳解
window.open是網(wǎng)頁中經(jīng)常遇到的彈出窗口代碼,不是網(wǎng)絡(luò)中比較反感的那類彈出代碼,下面這篇文章主要給大家介紹了關(guān)于JavaScript設(shè)置彈出式獨(dú)立窗口頁面和window的方法,需要的朋友可以參考下2024-01-01JS中g(shù)etElementsByClassName與classList兼容性問題解決方案分析
這篇文章主要介紹了JS中g(shù)etElementsByClassName與classList兼容性問題解決方案,結(jié)合實(shí)例形式分析了getElementsByClassName與classList的使用方法、原理及兼容性問題的處理技巧,需要的朋友可以參考下2019-08-08怎么在下面的HTML里調(diào)用數(shù)組cs[]的值
怎么在下面的HTML里調(diào)用數(shù)組cs[]的值...2007-01-01JavaScript實(shí)現(xiàn)函數(shù)重載的代碼示例
在JavaScript中并沒有直接支持函數(shù)重載的機(jī)制,但是可以通過一些技巧來模擬函數(shù)重載的效果,比如使用參數(shù)判斷,使用默認(rèn)參數(shù),對(duì)象參數(shù),這些方法都可以實(shí)現(xiàn)類似函數(shù)重載的效果,所以本文就給大家介紹一下JavaScript如何實(shí)現(xiàn)函數(shù)重載,需要的朋友可以參考下2023-08-08