vue axios+定時器實現1秒實時數據刷新 頁面關閉後上一個頁面定時器訪問的pending請求,在vue實例銷燬時關閉定時器以及pending中的請求

項目當中列表查看目標雲主機的監控,頁面當中以定時器內每一秒發出一次請求方式來實現實時刷新數據,當點擊列表選項卡後,監控頁面刷新數據的axios請求有pending狀態,此時在列表頁(即父頁面)會彈出監控頁面(即子頁面)的彈框,實現目標:即在監控頁面切換到列表頁面時,關閉監控頁面的定時器和pending狀態請求。

會遇到的問題:

  1. 當打開監控頁面接口正常的時候,定時器正常運行,點擊切換列表頁後pending的請求完成,在列表頁會繼續執行後續邏輯,找不到對應的就會報錯,即走到服務器錯誤彈出框,因此會在此時彈出n個框。*************解決辦法:在頁面銷燬的時候將定時器關閉,在axios請求頭加上官網文檔介紹的關閉pending請求的東西,並在銷燬實例的生命週期函數當中將其關閉,並將axios.catch(){}中的代碼加上try{}catch(res){}
  2. 我在axios報錯的時候捕獲異常,彈框後跳轉列表頁當中,此時因爲前幾個pending的請求可能會導致定時器比第一個請求報錯需要執行的邏輯代碼要快,即在頂一個請求還未做出反應的時候,定時器可能已經執行多個axios請求,所以依然會在切換到列表頁彈出多個框。***************解決辦法:axios請求報錯之後就需要進行定時器關閉、取消pending請求和重置定時器。然後在data中定義一個執行標記,在彈框之前進行判斷此標記並在判斷內第一行執行標記取反,後續再執行彈框

這樣的結局辦法頁面當中可以解決,頁面上雖然看不出來,但是可以請求還是會多出幾個來,數據量非常龐大的情況下也不建議使用定時器這樣的方式來進行實時數據刷新(我這塊的數據量沒有非常多),數據量大想要實現頁面數據實時刷新,建議使用websocket和後臺進行長連接,在實例銷燬時關閉長連接即可,也不會出現這篇博文的情況。

data數據定義

data (){
	return {
		intervalTimer:null,//定時器
        axiosFlag:true//catch中的彈框標記
	}
}

方法、生命週期函數

destroyed (){
    clearInterval(this.intervalTimer)//關閉定時器
    this.intervalTimer=null  //重置定時器
},
mounted (){
	this.initTable();
},
methods:{
	initTable(){
		var _this=this
        let CancelToken = _this.$axios.CancelToken
        _this.axiosFlag=true//刷新頁面將此標記重置
         _this.intervalTimer=setInterval(function(){//定時調用接口
            _this.$axios.get(`/api/monitor/detail/${_this.serviceStatus.id}`, {
                cancelToken: new CancelToken(function executor(c) {//axios自帶關閉請求方法
                    _this.cancel = c
                    // console.log(c)
                    // 這個參數 c 就是CancelToken構造函數裏面自帶的取消請求的函數,這裏把該函數當參數用
                })
            }).then(res => {
                if(res.status === 200){
                    //處理頁面加載需要的數據
                    _this.info=res.data
                    _this.loadDiskUsage()
                    _this.loadMemoryUsage()
                }
            }).catch(res => {
                try{//捕獲異常(在接口請求不報錯的情況下,點擊列表頁還會出現彈框,因爲pending完成之後請求找不到對應的字段,這時候只需要try catch 捕獲異常即可)
                    _this.cancel()//取消pending中的請求
                    clearInterval(_this.intervalTimer) //關閉定時器
                    _this.intervalTimer=null //重置定時器
                    if(res.response.status === 500 || res.response.status === 404 || res.response.status === 504){
                        if(_this.axiosFlag){//報錯後是否彈窗標記,
                            _this.axiosFlag=false
                            _this.$message({
                                message: '系統錯誤,請重新查看!',
                                type: 'error',
                                onClose:res =>{
                                    _this.$router.push('serviceStatus')
                                }
                            });
                        }
                    }
                }catch(res){
                    // console.log(res)
                }
                
            })                    
        },1000)
	}
}

2020/5/6 vuex存儲請求路由跳轉利用cancelToken來關閉上一個頁面的請求

main.js

// 添加請求攔截器,在請求頭中加token
axios.interceptors.request.use(config => {
  config.cancelToken = new axios.CancelToken(function (cancel) {
    store.commit('pushToken', {cancelToken: cancel})
  })
  return config;
}, error => {
// 對請求錯誤做些什麼
  return Promise.reject(error);
});

state.js

let cancelTokenArr=[]
export default {
    cancelTokenArr
}

mutations.js

export default{
	pushToken (state, payload) {
        state.cancelTokenArr.push(payload.cancelToken)
    },
    clearToken (state) {
        state.cancelTokenArr.forEach(item => {
            item('路由跳轉取消上一頁的請求')
        })
        state.cancelTokenArr = []
    }
 }

router.js(next() 之前進行 清空store中的pending請求數組 達到關閉正在pending的請求 拋出異常)

// 配置路由權限
router.beforeEach((to, from, next) => {
    let getTokenPath=to.path
    // console.log(to.path)
    if(getTokenPath === '/single_sign_on'){//判斷是否是固定的權限訪問授權路由
        let token = to.query.token
        let appid = to.query.appid
        if(token){
            // 通過 token 訪問第三方api 獲取有效key進入首頁並將key存入localstorage 否則進入login
            axios.get('/inapi/login/index',{
                headers:{
                    token:token,
                    appid:appid
                }}).then(res => {
                    if(res.data.code === 0){
                        store.commit('set_xaiot_token_key',res.data.data.role)
                        store.commit('set_xaiot_token',token)
                        store.commit('set_username',res.data.data.role)
                        store.commit('clearToken')
                        next('/')
                    }else{
                        localStorage.clear()
                        sessionStorage.clear()
                        store.commit('clearToken')
                        next('/login')
                    }
            }).catch(res => {
                // console.log(res.data.msg,'error')
                localStorage.clear()
                sessionStorage.clear()
                store.commit('clearToken')
                next('/login')
            })
        }else{
            localStorage.clear()
            sessionStorage.clear()
            store.commit('clearToken')
            next('/login')
        }
    }
    let xaiot_token=store.state.xaiot_token
    if (to.meta.requireAuth) { // 判斷該路由是否需要登錄權限
        if (xaiot_token) { // 判斷本地是否存在access_token
          store.commit('clearToken')
            next()
        } else {
            // 未登錄,跳轉到登陸頁面,並且帶上 將要去的地址,方便登陸後跳轉。
            localStorage.clear()
            sessionStorage.clear()
            store.commit('clearToken')
            next('/login')
        }
    } else {
      store.commit('clearToken')
        next()
    }
  })
export default router
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章