const xhr = new XMLHttpReques() xhr.open('GET', '/api') xhr.onreadstatechange(() => { if(xhr.readState === '4' && /^2\d{2}/.test(xhr.status)) { // sucess } }) xhr.send() // 取消請求 xhr.abort()
最多見的案例就是當咱們點擊按鈕須要去請求數據,若是按鈕沒有坐任何限制的話,當快速屢次點擊按鈕,可能會同時發出好幾條相同的請求,形成服務器壓力,也有可能形成頁面數據不對,此時咱們通常經常使用的方法就是在axios的全局攔截中作一些限制和判斷來規避這種操做javascript
import axios from 'axios' // 將正在請求的地址存儲起來 const pending = [] const CancelToken = axios.CancelToken /** * config 請求的axios的配置信息 * c框架中用於取消的回調,在這也會用來判斷當前是請求階段仍是返回階段 */ const removePending = (config, c) => { const url = config.url const index = pending.findIndex(i => i === `${url}&${config.method}`) // 判斷要請求的的地址有沒有在pending中 if (index > -1) { c ? c('數據請求中……') : pending.splice(index, 1) } else { c && pending.push(`${url}&${config.method}`) } } // 超時設置 axios.defaults.timeout=5000 axios.interceptors.request.use(function(config) { // 請求以前判斷並添加到pending config.cancelToken = new CancelToken(c => { removePending(config, c) }) return config },function (error) { return Promise.reject(error) }) /*對響應攔截*/ axios.interceptors.response.use(function (response) { const res=response.data // 請求回來後刪除pending存儲 removePending(response.config) if(response.status !== 200){ return Promise.reject(res) }else{ return res; } }, function (error) { // 請求回來後刪除pending存儲 error.config && removePending(error.config) return Promise.reject(error); });
在一個帶有tabs的頁面中:
若是咱們點擊"5萬如下",此時出發加載數據,當頁面數據未返回的時候,又點擊了"5-10萬",此時會再次去請求數據,若是"5萬如下"的數據返回的比較慢,可能會將"5-10萬"返回的數據給頂掉,此時頁面顯示的數據雖然tags在"5-10萬",可是其實顯示的是上一個標籤的數據;因此咱們應該在切換標籤的時候,將當前標籤未返回的請求取消掉來防止這種混亂的事情發生;在vue模版頁面中:html
export default { data() { return { list: null, cancel: null } }, create() { this.getLists() } methods: { // 獲取數據 getLists() { const CancelToken = this.axios.CancelToken this.axios.get('/api',{ cancelToken: new CancelToken(c => { // 調用c就能夠取消此請求 this.cancel = c }) }).then(result => { this.lists = result.data }) }, // 每次切換標籤時先調用此函數,就能夠取消請求 cancelAxios() { this.cancel() }, changeTabs() { this.cancelAxios() this.getLists() } }, }
源碼路徑:axios/lib/cancel/CancelToken.js
vue
var Cancel = require('./Cancel'); function CancelToken(executor) { if (typeof executor !== 'function') { throw new TypeError('executor must be a function.'); } // 將new Promise裏面的reslove付值給外部的resolvePromise,能夠方便在外面控制promise內部的狀態改變 var resolvePromise; this.promise = new Promise(function promiseExecutor(resolve) { resolvePromise = resolve; }); var token = this; //上例中new CancelToken穿進去的c就是此處的cancel函數,調用c就至關於調用cancel函數 executor(function cancel(message) { if (token.reason) { return; } token.reason = new Cancel(message); // 更改promise的狀態,狀態改變後會執行下面的then方法 resolvePromise(token.reason); }); } CancelToken.prototype.throwIfRequested = function throwIfRequested() { if (this.reason) { throw this.reason; } }; CancelToken.source = function source() { var cancel; var token = new CancelToken(function executor(c) { cancel = c; }); return { token: token, cancel: cancel }; }; module.exports = CancelToken;
上接resolvePromise
方法
地址: axios/lib/adapters/xhr.js
java
if (config.cancelToken) { // 上面執行完取消後resolvePromise,會觸發下面的then方法 // 取消請求 config.cancelToken.promise.then(function onCanceled(cancel) { if (!request) { return; } request.abort(); reject(cancel); // Clean up request request = null; }); }
所學有限,若是有什麼地方分析錯誤,能夠評論出來
原文地址ios