簡介
axios的攔截器是一個(gè)非常優(yōu)秀的設(shè)計(jì)珊佣,借助它我們可以實(shí)現(xiàn)很多效果堂油,節(jié)省重復(fù)的代碼。
今天重點(diǎn)不是介紹axios,而是帶領(lǐng)大家實(shí)現(xiàn)一個(gè)在網(wǎng)絡(luò)較慢時(shí)彈出友好提示的攔截器祝钢。類似與下面的效果比规。
大家可以到這里來體驗(yàn): http://ngzhixiao.gitee.io/heiibaiitoy/articles/axios/slownetwork/index.html
如果大家是在電腦上訪問的話,可以打開控制臺(tái)的network選擇網(wǎng)絡(luò)的slow 3G會(huì)更接近真實(shí)的體驗(yàn)image.png
實(shí)現(xiàn)
// 記錄當(dāng)前請求發(fā)出但未返回的id
const requestMap = new Set()
function generateId(url) {
return url+new Date().getTime()+Math.random()
}
/**
* 慢網(wǎng)絡(luò)提示攔截器拦英,在網(wǎng)絡(luò)慢的情況提示用戶等待
*/
const slowNetworkInterceptor = function(axios, slowTime = 5000) {
if(!axios.defaults.headers.common.__config){
axios.defaults.headers.common.__config = {}
}
axios.defaults.headers.common.__config.slowNetworkConfig = {
slowTime, // 定義網(wǎng)絡(luò)慢的條件
close: false, // 允許在某些接口關(guān)閉提示
}
axios.interceptors.request.use(config => {
const snc = config.headers.common.__config.slowNetworkConfig
if(snc.close) return config
const id = generateId(config.url)
requestMap.add(id)
snc.id = id
setTimeout(() => {
if(requestMap.has(id)) {
Toast("網(wǎng)絡(luò)似乎正在開小差蜒什,請耐心等待噢(? ˙o˙)?")
requestMap.delete(id)
}
}, snc.slowTime);
return config
}, err => Promise.reject(err))
axios.interceptors.response.use(res => {
const snc = res.config.headers.__config.slowNetworkConfig
if(snc.close) return res
requestMap.delete(snc.id)
return res
}, err => {
const snc = err.config.headers.__config.slowNetworkConfig
if(snc.close) return Promise.reject(err)
requestMap.delete(snc.id)
return Promise.reject(err)
})
return axios
}
slowNetworkInterceptor(axios)
代碼如上所示。
在每次請求時(shí)會(huì)生成一個(gè)id并將其存儲(chǔ)到請求配置config中龄章,用來標(biāo)記這個(gè)請求吃谣。在最開始的時(shí)候我們定義了一個(gè)記錄發(fā)出但未返回的網(wǎng)絡(luò)請求的requestMap,將這個(gè)請求的id記錄下來做裙。然后開啟一個(gè)定時(shí)器(我們默認(rèn)給它一個(gè)5s)岗憋,如果5s內(nèi)請求返回了,就在返回的攔截器刪除掉對應(yīng)的id锚贱;如果5s內(nèi)還未返回仔戈,我們就彈框提示用戶當(dāng)前網(wǎng)絡(luò)較慢。
其中有一個(gè)細(xì)節(jié)拧廊,為什么id和定時(shí)器時(shí)長的信息不直接放到請求對象的config中而是放在headers上呢监徘?放到headers上不久隨著請求發(fā)出去了嗎?
其實(shí)這axios的實(shí)現(xiàn)有關(guān)吧碾,在真正的發(fā)出請求前凰盔,axios會(huì)把config中的參數(shù)進(jìn)行一個(gè)合并操作,但是只會(huì)合并它定義的一些參數(shù)倦春,所以如果直接放到config上就會(huì)被排除掉户敬,而對headers時(shí)會(huì)進(jìn)行一個(gè)深拷貝,同時(shí)將common提上一級(jí)睁本,這也能解釋在請求攔截中設(shè)置在common中的參數(shù)為什么在返回?cái)r截中能直接在headers上拿到尿庐。
這會(huì)導(dǎo)致我們在請求頭多一個(gè)參數(shù),是這樣的:__config: [object Object]呢堰,但在大多數(shù)情況下這沒什么影響抄瑟。
總結(jié)
這只是攔截器的其中一種用法,其實(shí)在實(shí)際的開發(fā)過程中枉疼,我們還可以通過攔截器實(shí)現(xiàn)請求的簽名皮假、請求數(shù)據(jù)的加解密、甚至能實(shí)現(xiàn)緩存請求的緩存等操作往衷。
axios是一個(gè)設(shè)計(jì)很巧妙的庫钞翔,而且他的代碼很短,是學(xué)習(xí)優(yōu)秀開源庫很好的例子席舍,推薦有時(shí)間都能去看看它的源碼。