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