vue路由切换时取消之前的所有请求操作


Posted in Javascript onSeptember 01, 2020

在main.js文件里

import router from 'router/';
import Vue from 'vue';
Vue.Cancel = [];
router.beforeEach((to, from, next) => {
 while (Vue.Cancel.length > 0) {
 Vue.Cancel.shift()('cancel');
 }
 next();
})

ajax文件

import Vue from 'vue';
import axios from 'axios';
import VueAxios from 'vue-axios';

Vue.use(VueAxios, axios);

// 导入封装的回调函数
import {
 cbs,
 gbs
} from 'config/';

// 动态设置本地和线上接口域名
Vue.axios.defaults.baseURL = gbs.host;

/**
 * 封装axios的通用请求
 * @param {string} type get或post
 * @param {string} url 请求的接口URL
 * @param {object} data 传的参数,没有则传空对象
 * @param {object} urlParams url传参
 * @param {Function} fn 回调函数
 * @param {boolean} tokenFlag 是否需要携带token参数,为true,不需要;false,需要。一般除了登录,都需要
 */
export default function ({
 type,
 path,
 data,
 params,
 urlParams,
 fn,
 errFn,
 tokenFlag,
 headers,
 opts
} = {}) {

 var options = {
 method: type,
 url: path,
 params: params,
 headers: headers && typeof headers === 'object' ? headers : {},
 cancelToken: new axios.CancelToken(function (cancel) {
  Vue.Cancel && Vue.Cancel.push(cancel)
 }) 
 };

 //检测接口权限
 var api_flag = true;
 if (options.url && options.url.indexOf(gbs.host) && this.$store.state.user.userinfo.access_status === 1) {
 var url = options.url.replace(gbs.host, '');
 var api_routers = this.$store.state.user.userinfo.api_routers;
 if (!api_routers || !api_routers.constructor === Object || !api_routers[url]) {
  api_flag = false;
 }
 }

 var urlParamsArray = [];
 if (api_flag === true) {
 options[type === 'get' ? 'params' : 'data'] = data;

 // 用于url传参
 if (typeof (urlParams) == "object") {
  for (var k in urlParams) {
  urlParamsArray.push(k + '=' + urlParams[k])
  }
  options.url += '?' + urlParamsArray.join('&');
 }
 if (typeof (urlParams) == "string" || typeof (urlParams) == "number") {
  options.url += urlParams;
 }

 if(options.url.indexOf('?') > -1){
  options.url += '&_=' + (new Date()).getTime();
 }else{
  options.url += '?_=' + (new Date()).getTime();
 }

 // 分发显示加载样式任务
 this.$store.dispatch('show_loading');

 if (tokenFlag !== true) {
  //如果你们的后台不会接受headers里面的参数,打开这个注释,即实现token通过普通参数方式传
  // data.token = this.$store.state.user.userinfo.token;

  options.headers.token = this.$store.state.user.userinfo.token;
 }

 //扩展Promise使支持finally(),用了babel就不用手写了^.^
 // Promise.prototype.finally=function(callback){
 // let Promise = this.constructor;
 // return this.then(
 //  value => Promise.resolve(callback()).then(() => value),
 //  reason => Promise.resolve(callback()).then(() => { throw reason })
 // );
 // };
 //发送请求
 return new Promise((resolve, reject)=>{
  Vue.axios(options).then((res) => {
  this.$store.dispatch('hide_loading');
  if (res.data[gbs.api_status_key_field] === gbs.api_status_value_field || (res.status === gbs.api_status_value_field && !res.data[gbs.api_status_key_field])) {
   fn(res.data);
  } else {
   if (gbs.api_custom[res.data[gbs.api_status_key_field]]) {
   gbs.api_custom[res.data[gbs.api_status_key_field]].call(this, res.data);
   } else {
   cbs.statusError.call(this, res.data);
   if (errFn) {
    errFn.call(this, res.data);
   }
   }
  }
  resolve(res.data);
  }).catch((err) => {
  if(err.response && err.response.status !== 403){
   try{
   errFn?errFn.call(this, this.$$lib__.isObject(err.response.data) ? err.response.data : {}):null;
   }catch(err){
   console.error(err.message);
   }
  }
  if(err.response && err.response.data === ''){
   cbs.statusError.call(this, {status: err.response.status});
  } else if (err.response && this.$$lib__.isObject(err.response.data)) {
   cbs.statusError.call(this, err.response.data);
  }else if(err.response){
   cbs.requestError.call(this, err);
  } else {
   console.error('Error from ', '"'+path+'".', err.message);
  }
  reject(err);
  });
 });
 } else {
 this.$alert('您没有权限请求该接口!', '请求错误', {
  confirmButtonText: '确定',
  type: 'warning'
 });
 }
};

核心代码为cancelToken参数

var options = {
 method: type,
 url: path,
 params: params,
 headers: headers && typeof headers === 'object' ? headers : {},
 cancelToken: new axios.CancelToken(function (cancel) {
  Vue.Cancel && Vue.Cancel.push(cancel)
 }) 
 };

补充知识:problem:vue组件局部刷新,在组件销毁(destroyed)时取消刷新无效问题

场景:

一个群发消息列表(数组)

列表下有多条消息(元素)

每条正在发送的消息数据状态需要实时刷新,发送完成时需要显示成功提示符合且不需要刷新,然后3秒消失。首次显示列表时,已经成功的状态不显示这个成功提示符。

1、定位确定采用局部刷新

2、进入消息列表请求获取列表数据的接口,完成发送的消息不需显示完成状态

3、正在发送的消息首次渲染时就调用setTimeout轮询刷新当前消息的接口,完成时,显示完成状态(新增一个完成状态的字段)

4、页面销毁时,还在发送的消息也取消刷新

误区:

1、每条消息没有抽成一个单独的组件,想要首次渲染组件调用刷新接口时,只能通过定义全局map变量来映射每条消息的刷新接口的定时器,明显增加业务开发的复杂度,增加了一些不确定性的bug风险。

每条消息抽成组件之后,就可以在组件中的mounted中去调用刷新的接口,页面销毁时取消刷新可以在destroyed里面去销毁。

2、这里的一个误区是在destroyed里面去清除定时器的id,导致调用了destroyed钩子刷新的定时器还是无法清除。将定时器id当做一个属性值存在了每条数据所属的对象中,然后在子组件(每条消息所属的)中的destroyed中去读取该对象的当前的定时器属性,因为读出来是undifined,其实并没有拿到当前消息正在执行的定时器,所以清除不掉。

组件使用有误,每一个组件都是一个独立的元素,其中定义的变量也是私有的,定时器id定在当前组件的data中就可以了,不需要再在数组中的每一条消息中定一个专属的定时器id。

抽象出来的简单版刷新数据,5秒后取消刷新。

let intervalId = null
function init() {
 this.refresh()
}

function refresh() {
 intervalId = setTimeout(() => {
   this.getRefreshData()
  }, 2000);
}

function getRefreshData() {
 console.log('start get data.....', intervalId)
 setTimeout(() => {
  console.log('get data.....')
  this.refresh()
 }, 100);
 
}

function stopRefresh() {
 console.log('stop....', intervalId)
 clearInterval(intervalId)
}

this.init()
setTimeout(() => {
 this.stopRefresh()
}, 5000);

以上这篇vue路由切换时取消之前的所有请求操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
ExtJS 入门
Oct 29 Javascript
javascript实现的一个带下拉框功能的文本框
May 08 Javascript
javascript获取重复次数最多的字符
Jul 08 Javascript
jQuery实现查找链接文字替换属性的方法
Jun 27 Javascript
jQuery和CSS仿京东仿淘宝列表导航菜单
Jan 04 Javascript
基于Bootstrap框架菜鸟入门教程(推荐)
Sep 17 Javascript
Bootstrap Table快速完美搭建后台管理系统
Sep 20 Javascript
详解Javascript 中的 class、构造函数、工厂函数
Dec 20 Javascript
vue项目实战总结篇
Feb 11 Javascript
微信小程序 wepy框架与iview-weapp的用法详解
Apr 10 Javascript
React传值 组件传值 之间的关系详解
Aug 26 Javascript
Vue v-for循环之@click点击事件获取元素示例
Nov 09 Javascript
jQuery实现动态加载瀑布流
Sep 01 #jQuery
vue Treeselect下拉树只能选择第N级元素实现代码
Aug 31 #Javascript
vue treeselect获取当前选中项的label实例
Aug 31 #Javascript
vue 监听 Treeselect 选择项的改变操作
Aug 31 #Javascript
搭建vscode+vue环境的详细教程
Aug 31 #Javascript
vue组件中实现嵌套子组件案例
Aug 31 #Javascript
vue 项目中当访问路由不存在的时候默认访问404页面操作
Aug 31 #Javascript
You might like
浅谈web上存漏洞及原理分析、防范方法(文件名检测漏洞)
2013/06/29 PHP
php模拟ping命令(php exec函数的使用方法)
2013/10/25 PHP
PHP和Shell实现检查SAMBA与NFS Server是否存在
2015/01/07 PHP
浅谈htmlentities 、htmlspecialchars、addslashes的使用方法
2016/12/09 PHP
PHP封装的XML简单操作类完整实例
2017/11/13 PHP
YII框架页面缓存操作示例
2019/04/29 PHP
该如何加载google-analytics(或其他第三方)的JS
2010/05/13 Javascript
Jquery图片滚动与幻灯片的实例代码
2013/04/08 Javascript
jQuery.holdReady()方法用法实例
2014/12/27 Javascript
修复bash漏洞的shell脚本分享
2014/12/31 Javascript
JS设置网页图片vspace和hspace属性的方法
2015/04/01 Javascript
CSS3实现动态背景登录框的代码
2015/07/28 Javascript
javascript断点调试心得分享
2016/04/23 Javascript
jQuery中使用animate自定义动画的方法
2016/05/29 Javascript
深入了解JavaScript的逻辑运算符(与、或)
2016/12/20 Javascript
浅谈jQuery操作类数组的工具方法
2016/12/23 Javascript
详解Node.js串行化流程控制
2017/05/04 Javascript
input file样式修改以及图片预览删除功能详细概括(推荐)
2017/08/17 Javascript
vue cli升级webapck4总结
2018/04/04 Javascript
又拍云 Node.js 实现文件上传、删除功能
2018/10/28 Javascript
vue基础之事件简写、事件对象、冒泡、默认行为、键盘事件实例分析
2019/03/11 Javascript
python实现应用程序在右键菜单中添加打开方式功能
2017/01/09 Python
Numpy 将二维图像矩阵转换为一维向量的方法
2018/06/05 Python
python实现彩色图转换成灰度图
2019/01/15 Python
使用pandas实现连续数据的离散化处理方式(分箱操作)
2019/11/22 Python
对Tensorflow中tensorboard日志的生成与显示详解
2020/02/04 Python
Python Selenium实现无可视化界面过程解析
2020/08/25 Python
法国最大的在线眼镜店:EasyLunettes
2019/08/26 全球购物
酒店爱岗敬业演讲稿
2014/09/02 职场文书
卖车协议书范例
2014/09/16 职场文书
学校领导班子四风对照检查材料
2014/09/27 职场文书
领导干部作风建设自查报告
2014/10/23 职场文书
远程教育学习心得体会
2016/01/23 职场文书
2016年国庆节67周年活动总结
2016/04/01 职场文书
Go 在 MongoDB 中常用查询与修改的操作
2021/05/07 Golang
JS代码编译器Monaco使用方法
2021/06/11 Javascript