1. 程式人生 > 程式設計 >vue路由切換時取消之前的所有請求操作

vue路由切換時取消之前的所有請求操作

在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,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路由切換時取消之前的所有請求操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。