vue項(xiàng)目中created()被調(diào)用多次的踩坑實(shí)戰(zhàn)
一、問(wèn)題描述
最近碰到一個(gè)奇怪的生產(chǎn)問(wèn)題:
正常情況下、前端頁(yè)面會(huì)請(qǐng)求一次后臺(tái)、然后后臺(tái)返回信息("處理成功"或"處理失敗")、前端展示;
后臺(tái)用aop+redis寫(xiě)了一個(gè)防止重復(fù)調(diào)用的方法,如果5s內(nèi)同一個(gè)用戶重復(fù)調(diào)用同一個(gè)接口,就返回"請(qǐng)勿重復(fù)調(diào)用",前端就會(huì)展示這個(gè)。
但是,某幾個(gè)頁(yè)面,前端總是會(huì)重復(fù)調(diào)用后端2次,導(dǎo)致用戶只能看到"請(qǐng)勿重復(fù)調(diào)用",無(wú)法確認(rèn)本次操作是成功還是失敗,嚴(yán)重影響了用戶的正常使用。(雖然是處理成功,但是顯示不出來(lái)…)
一開(kāi)始還懷疑是不是后端的問(wèn)題,排查了半天,終于鎖定了,是前端的問(wèn)題,vue項(xiàng)目中的created()方法被調(diào)用了2次。
繼續(xù)排查,發(fā)現(xiàn)從正常頁(yè)面跳轉(zhuǎn)到這個(gè)問(wèn)題頁(yè)面時(shí),確實(shí)只跳轉(zhuǎn)了1次,按理說(shuō)created()方法應(yīng)該也只觸發(fā)1次的,但是就是不知道為什么觸發(fā)了2次。
二、排查過(guò)程
1.從頭開(kāi)始排查前端項(xiàng)目,vue項(xiàng)目首先會(huì)加載main.js,發(fā)現(xiàn)這個(gè)文件里有:
import Vcon from './assets/js/vcon' new Vcon({ env: ENV }, () => { new Vue({ router, render: h => h(App) }).$mount('#app') })
發(fā)現(xiàn)這個(gè)文件里,并不是普通的使用new Vue()
創(chuàng)建的頁(yè)面,而是外面有封裝了一個(gè)new Vcon()
方法,并傳了2個(gè)參數(shù),其中第一個(gè)參數(shù)是{ env: ENV }
,第二個(gè)參數(shù)是 () => { new Vue({ router, render: h => h(App) }).$mount('#app') }
2.繼續(xù),查看./assets/js/vcon.js
文件,發(fā)現(xiàn)這個(gè)文件里有類(lèi)似這樣的:
class Vcon { constructor (opt, callBack) { this.env = opt.env || '' // 記錄代碼環(huán)境 this.callBack = callBack // 記錄回調(diào)函數(shù) // 如果是生產(chǎn)環(huán)境 if (this.env !== 'test') { this.prodInit() typeof this.callBack === 'function' && this.callBack() return } // 如果是測(cè)試環(huán)境 if (this.env === 'test') { this.testInit() return } } testInit () { import('vconsole').then(({ default: VConsole }) => { new VConsole() console.log('測(cè)試vconsole加載完成') typeof this.callBack === 'function' && this.callBack() }) } prodInit () { let _that = this window.ISALES.callApp('getUserInfoByNative', { callback: function (userInfo) { if (userInfo.code === '0') { _that.betterStaffNUmber = userInfo.msg.staffNumber _that.betterHandler(userInfo) return } alert('獲取sdk出錯(cuò),請(qǐng)稍后再試') } }) } betterHandler (userInfo) { if (userInfo.msg.userCode == 'admin') { import('vconsole').then(({ default: VConsole }) => { new VConsole() console.log(`admin的vconsole加載完成`) typeof this.callBack === 'function' && this.callBack() }) return }else{ this.callBack() } } }
其中,當(dāng)上一步執(zhí)行new Vcon()
時(shí),實(shí)際執(zhí)行的就是這里的constructor ()
方法;
如果是測(cè)試環(huán)境,那就執(zhí)行testInit ()
方法,這個(gè)還是比較明顯的,用來(lái)展示vconsole(測(cè)試環(huán)境一直正常,沒(méi)有復(fù)測(cè)出來(lái)問(wèn)題);
如果是生產(chǎn)環(huán)境,那就執(zhí)行prodInit()
方法,然后執(zhí)行typeof this.callBack === 'function' && this.callBack()
方法(這里感覺(jué)有些問(wèn)題,先繼續(xù)看);
prodInit()
方法里,會(huì)執(zhí)行window.ISALES.callApp
方法,這個(gè)是個(gè)sdk方法(這個(gè)前端項(xiàng)目是vue項(xiàng)目,可以打包后把靜態(tài)頁(yè)面部署在服務(wù)器上;sdk方法是app和ios里的方法,前端只能這樣才能調(diào)用到、待sdk方法處理完后會(huì)觸發(fā)callback方法);
sdk方法中,會(huì)執(zhí)行betterHandler()
方法,意思是,如果當(dāng)前app/ios的登錄人是admin,那就顯示vconsole,否則就不顯示。
3.根據(jù)生產(chǎn)created()方法被調(diào)用2次、而測(cè)試正常的現(xiàn)象,排查到問(wèn)題方法位置:
// 如果是生產(chǎn)環(huán)境 if (this.env !== 'test') { this.prodInit() typeof this.callBack === 'function' && this.callBack() return }
因?yàn)閜rodInit()方法的邏輯中,正常情況下,已經(jīng)調(diào)用過(guò)一次typeof this.callBack === 'function' && this.callBack()
了,然而執(zhí)行完prodInit()方法后,又會(huì)調(diào)用一次typeof this.callBack === 'function' && this.callBack()
,所以才導(dǎo)致created()方法被重復(fù)調(diào)用了2次。
4.正確代碼如下:
// 如果是生產(chǎn)環(huán)境 if (this.env !== 'test') { this.prodInit() //這里導(dǎo)致了重復(fù)created() //typeof this.callBack === 'function' && this.callBack() return }
修改后,發(fā)布生產(chǎn),終于恢復(fù)了正常。
三、備注
1.vue項(xiàng)目中,有時(shí)會(huì)自動(dòng)優(yōu)化代碼格式,導(dǎo)致if后面沒(méi)有大括號(hào)、只有1句,滿足條件就執(zhí)行、不滿足就不執(zhí)行,需要注意。
2.有時(shí),if沒(méi)有else,而是if中結(jié)尾有個(gè)return,此時(shí)也類(lèi)似else,但是容易忽略,需要注意。(這個(gè)也是自動(dòng)優(yōu)化格式的?還是故意寫(xiě)的難懂了?)
3.typeof this.callBack === 'function' && this.callBack()
,這個(gè)的意思是,如果this.callBack
是function
類(lèi)型的,那就會(huì)執(zhí)行后面的this.callBack()
方法,然后繼續(xù)下一步;如果不是function
類(lèi)型的,那就不執(zhí)行后面的方法,直接繼續(xù)下一步。(又一個(gè)不好理解的高級(jí)寫(xiě)法,用if不好嗎?)
4.正常情況下,vue頁(yè)面的created()方法會(huì)在頁(yè)面初始化的時(shí)候執(zhí)行1次;但是如果代碼有問(wèn)題,就會(huì)導(dǎo)致created()方法會(huì)在頁(yè)面初始化的時(shí)候執(zhí)行2次或多次(如本文),這個(gè)坑需要注意。
總結(jié)
到此這篇關(guān)于vue項(xiàng)目中created()被調(diào)用多次的踩坑的文章就介紹到這了,更多相關(guān)vue created()被調(diào)用多次內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue 動(dòng)態(tài)樣式綁定 class/style的寫(xiě)法小結(jié)
這篇文章主要介紹了vue 動(dòng)態(tài)樣式綁定 class/style的寫(xiě)法小結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03vue開(kāi)發(fā)頁(yè)面自適應(yīng)屏幕尺寸的實(shí)例代碼
使用vue開(kāi)發(fā)的頁(yè)面都是通過(guò)px設(shè)置它的尺寸,如果換了一個(gè)不同尺寸的屏幕就會(huì)出現(xiàn)頁(yè)面排版錯(cuò)亂,顯示不完整等情況,下面通過(guò)插件將px裝換為rem單位適應(yīng)不同尺寸的屏幕,需要的朋友可以參考下2022-12-12如何使用Vue做個(gè)簡(jiǎn)單的比較兩個(gè)數(shù)字大小頁(yè)面
這篇文章主要給大家介紹了關(guān)于如何使用Vue做個(gè)簡(jiǎn)單的比較兩個(gè)數(shù)字大小頁(yè)面的相關(guān)資料,實(shí)現(xiàn)一個(gè)比較兩個(gè)數(shù)字大小的頁(yè)面,練習(xí)Vue實(shí)例的創(chuàng)建、數(shù)據(jù)綁定和事件監(jiān)聽(tīng)方法,需要的朋友可以參考下2023-10-10使用Element時(shí)默認(rèn)勾選表格toggleRowSelection方式
這篇文章主要介紹了使用Element時(shí)默認(rèn)勾選表格toggleRowSelection方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10vue實(shí)現(xiàn)echarts餅圖/柱狀圖點(diǎn)擊事件實(shí)例
echarts原生提供了相應(yīng)的API,只需要在配置好echarts之后綁定相應(yīng)的事件即可,下面這篇文章主要給大家介紹了關(guān)于vue實(shí)現(xiàn)echarts餅圖/柱狀圖點(diǎn)擊事件的相關(guān)資料,需要的朋友可以參考下2023-06-06解決vue多個(gè)路由共用一個(gè)頁(yè)面的問(wèn)題
下面小編就為大家分享一篇解決vue多個(gè)路由共用一個(gè)頁(yè)面的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03vue中實(shí)現(xiàn)左右聯(lián)動(dòng)的效果
這篇文章主要介紹了vue中實(shí)現(xiàn)左右聯(lián)動(dòng)的效果,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-06-06vue實(shí)現(xiàn)簡(jiǎn)單的購(gòu)物車(chē)小案例
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)簡(jiǎn)單的購(gòu)物車(chē)小案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07詳解.vue文件中style標(biāo)簽的幾個(gè)標(biāo)識(shí)符
這篇文章主要介紹了詳解.vue文件中style標(biāo)簽的幾個(gè)標(biāo)識(shí)符,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07