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 相关文章推荐
jQuery 性能优化手册 推荐
Feb 23 Javascript
纯JavaScript实现的完美渐变弹出层效果代码
Apr 02 Javascript
javaScript同意等待代码实现心得
Jan 01 Javascript
jQuery.extend 函数详解
Feb 03 Javascript
Extjs中通过Tree加载右侧TabPanel具体实现
May 05 Javascript
JQuery中基础过滤选择器用法实例分析
May 18 Javascript
JavaScript仿支付宝6位数字密码输入框
Dec 29 Javascript
JS实现JSON.stringify的实例代码讲解
Feb 07 Javascript
jquery-file-upload 文件上传带进度条效果
Nov 21 jQuery
基于AngularJs select绑定数字类型的问题
Oct 08 Javascript
Js逆向实现滑动验证码图片还原的示例代码
Mar 10 Javascript
vue打开新窗口并实现传参的图文实例
Mar 04 Vue.js
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
曾在DC漫画界反派角色扮演的演员,谁才是你心目中的小丑之王?
2020/04/09 欧美动漫
PHP中date()日期函数有关参数整理
2011/07/19 PHP
PHP基于SMTP协议实现邮件发送实例代码
2017/04/27 PHP
php实现数组中出现次数超过一半的数字的统计方法
2018/10/14 PHP
PHP的mysqli_ssl_set()函数讲解
2019/01/23 PHP
php时间戳转换代码详解
2019/08/04 PHP
一个高效的JavaScript压缩工具下载集合
2007/03/06 Javascript
JavaScript创建命名空间(namespace)的最简实现
2007/12/11 Javascript
JS定义回车事件(实现代码)
2013/07/08 Javascript
JS对img标签进行优化使用onerror显示默认图像
2014/04/24 Javascript
node.js中的http.createServer方法使用说明
2014/12/14 Javascript
JavaScript表单验证实例之验证表单项是否为空
2016/01/10 Javascript
Vue实例中生命周期created和mounted的区别详解
2017/08/25 Javascript
完美解决手机浏览器顶部下拉出现网页源或刷新的问题
2017/11/30 Javascript
JavaScript函数、闭包、原型、面向对象学习笔记
2018/09/06 Javascript
koa2+vue实现登陆及登录状态判断
2019/08/15 Javascript
vue+elementUi图片上传组件使用详解
2019/08/20 Javascript
Node.js+Vue脚手架环境搭建的方法步骤
2020/03/08 Javascript
vue项目中使用rem,在入口文件添加内容操作
2020/11/11 Javascript
Vue2.x-使用防抖以及节流的示例
2021/03/02 Vue.js
[02:44]2014DOTA2 国际邀请赛中国区预选赛 大神红毯秀
2014/05/25 DOTA
浅析Python中的join()方法的使用
2015/05/19 Python
解决python中os.listdir()函数读取文件夹下文件的乱序和排序问题
2018/10/17 Python
深入解析python中的实例方法、类方法和静态方法
2019/03/11 Python
python中的数据结构比较
2019/05/13 Python
pyqt5对用qt designer设计的窗体实现弹出子窗口的示例
2019/06/19 Python
Python面向对象魔法方法和单例模块代码实例
2020/03/25 Python
Sisley法国希思黎中国官网:享誉全球的奢华植物美容品牌
2019/06/30 全球购物
说说在weblogic中开发消息Bean时的persistent与non-persisten的差别
2013/04/07 面试题
新锐科技Java程序员面试题
2016/07/25 面试题
餐饮业会计岗位职责
2013/12/19 职场文书
酒店管理求职信
2014/06/09 职场文书
反四风个人对照检查材料思想汇报
2014/09/25 职场文书
中秋客户感谢信
2015/01/22 职场文书
会议通知格式范文
2015/04/15 职场文书
python实现商品进销存管理系统
2022/05/30 Python