问题:
在SPA模式开发当中,比如VUE ,当前路由切换的时候如何终止正在发生的异步请求呢,
结果:
假如请求超时并且有设定超时时间。有一堆的异步请求在执行,当用户切换到另一个页面,这些请求还未终止,并且当服务器响应之后,反馈的结果不是当前页面所期待的。最终会误导用户造成一些不必要的结果。也给web 造成性能问题。
解决方案:
把执行的请求存入,当路由切换的时候终止里的异步请求。
首先搞一棵树来存储请求
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)let store = new Vuex.Store({ state:{ requests:[] }})new Vue({ el: '#app', router: router, render: h => h(App), store})
利用ajax请求和终止
var xhr = $.ajax({type:'POST', url:'xxxsx', data:'', success:function(){ alert('ok'); }})//xhr.abort() 终止请求this.$store.state.requests.push(xhr)
利用superagent请求 和终止
const request = require('superagent')var xhr = request('post','/api/xxxx/xxxx')xhr.send(data)//xhr.query(data) //get 传参xhr.end((err,res)=>{ ...todo...})//xhr.abort() 终止请求this.$store.state.requests.push(xhr)
利用axios 请求
import axios from 'axios'var CancelToken = axios.CancelToken;var source = CancelToken.source();axios.get('/api/xxxxx/xxxxx', { cancelToken: source.token}).catch(function(thrown) { if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // 处理错误 }});// 取消请求(message 参数是可选的)//source.cancel('Operation canceled by the user.');this.$store.state.requests.push(source)
利用vue-resource请求
import Vue from 'vue'import req from 'vue-resource'Vue.use(req)this.$http.get('/someUrl', { before(request) { this.$store.state.requests.push(request) //request.abort(); 终止请求 } }).then(response => { // success callback }, response => { // error callback });
利用fetch 请求
fetch 貌似无法监控读取进度和终端请求,他没有timeout机制,没有progress提示,但是可以利用Promise 来实现终止
var _fetch = (function(fetch){ return function(url,options){ var abort = null; var abort_promise = new Promise((resolve, reject)=>{ abort = () => { reject('abort.'); console.info('abort done.'); }; }); var promise = Promise.race([ fetch(url,options), abort_promise ]); promise.abort = abort; return promise; };})(fetch);var xhr = _fetch('/api/xxx/xxxx',{methods:'POST',body:data});xhr.then(function(res) { console.log('response:', res);}, function(e) { console.log('error:', e);});xhr.abort(); //终止this.$store.state.requests.push(xhr)
那么知道如何终止请求,然后也存储了请求实例,剩下的只要监听路由就行了
let router = new Router({....})//每次路由改变之前终止所有的请求实例router.beforeEach(function (to, from, next) { this.$store.state.requests.forEach(xhr=>xhr.abort()) //终止所有的请求实例 this.$store.state.requests =[] //执行完清空,等待下一次的页面的请求装载 next()})
这种只是假设,自然请求完成之后最好,还是手动释放树的请求示例。例如ajax 请求完成之后 在complite 里面 splice store里面的实例。
[完]