您好,登錄后才能下訂單哦!
這篇文章主要介紹了vue中的eventBus會(huì)產(chǎn)生內(nèi)存泄漏嗎,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
eventBus是在vue中經(jīng)常用來(lái)解決跨組件消息傳遞的問(wèn)題,但對(duì)它的使用要特別注意,否則會(huì)產(chǎn)生很?chē)?yán)重的后果。
本文介紹了eventBus的實(shí)現(xiàn)原理,并介紹它如何在vue中使用,并舉了一個(gè)具體的例子來(lái)說(shuō)明,如果使用不當(dāng),它會(huì)造成內(nèi)存泄漏。
要注意eventBus并不是前端的概念。
由greenrobot [1] 組織貢獻(xiàn)(該組織還貢獻(xiàn)了greenDAO),一個(gè)Android事件發(fā)布/訂閱輕量級(jí)框架,
功能:通過(guò)解耦發(fā)布者和訂閱者簡(jiǎn)化Android事件傳遞 [2]
EventBus可以代替Android傳統(tǒng)的Intent,Handler,Broadcast或接口函數(shù),在Fragment,Activity,Service線(xiàn)程之間傳遞數(shù)據(jù),執(zhí)行方法。
特點(diǎn):代碼簡(jiǎn)潔,是一種發(fā)布訂閱設(shè)計(jì)模式(觀察者設(shè)計(jì)模式)。
eventBus在vue中的實(shí)現(xiàn);
在vue使用eventBus;
使用不當(dāng)?shù)膯?wèn)題:多次執(zhí)行回調(diào);內(nèi)存泄漏;
解決方案:及時(shí)調(diào)用$off
eventBus是事件總線(xiàn)的意思,它本質(zhì)上是一個(gè)發(fā)布訂閱者實(shí)現(xiàn),在vue2.X中,vue實(shí)例上提供了$on,$emit,$off這三個(gè)方法,分別用來(lái)添加觀察者,發(fā)布事件,取消訂閱這三個(gè)操作。
所以,我們可以直接把一個(gè)vue實(shí)例掛到Vue的原型上來(lái)充當(dāng)組件相互通信的中介。
Vue.prototype.$eventBus = new Vue()
這樣一來(lái),所有的Vue組件都可以沿著原型鏈找到這個(gè)$eventBus,從而訪(fǎng)問(wèn)$on, $off,$emit。
它可以幫助我們實(shí)現(xiàn)跨組件的通信。
在根組件中發(fā)布事件,在兩個(gè)子組件中去監(jiān)聽(tīng)事件。
<div id="app"> <h3>eventBus的基本使用</h3> <com1></com1> <com2></com2> </div> <script> Vue.prototype.$eventBus = new Vue() Vue.component('com1', { template:`<div>com1</div>`, created () { this.$eventBus.$on('event1', function f1(d){ conse.log(d, 'com1 listen... event1') }) }, }) Vue.component('com2', { template:`<div>com2</div>`, created () { this.$eventBus.$on('event2', function f2(d) { conse.log(d, 'com2 listen... event2') }) } }) var vm = new Vue({ el: '#app', created () { setInterval( () => { const d = Date.now() this.$eventBus.$emit('event1', d) this.$eventBus.$emit('event2', d) }, 3000) } }) </script>
在創(chuàng)建com1組件時(shí),訂閱event1事件;在創(chuàng)建com2組件時(shí),訂閱event2事件;在創(chuàng)建根組件(vue實(shí)例)時(shí),開(kāi)啟定時(shí)器:每隔3s發(fā)布事件,這樣的話(huà),com1和com2就都可以收到事件,并執(zhí)行對(duì)應(yīng)的回調(diào)。
效果如下:
如果不及時(shí)取消訂閱,則回調(diào)函數(shù)仍會(huì)執(zhí)行,更嚴(yán)重的是,如果在事件處理回調(diào)函數(shù)中引用了外部變量形成了閉包,則會(huì)導(dǎo)致內(nèi)存泄漏。
下面的代碼說(shuō)明這個(gè)問(wèn)題。
在根組件(vue實(shí)例)中,補(bǔ)充一個(gè)數(shù)據(jù)項(xiàng)showCom1,并配置v-if指令來(lái)實(shí)現(xiàn)銷(xiāo)毀和重建com1組件。
<div id="app"> <h3>不及時(shí)取消訂閱的問(wèn)題</h3> <button @click="showCom1=!showCom1"> {{showCom1 ? "銷(xiāo)毀" : "重建"}}組件1 </button> <com1 v-if="showCom1"></com1> <com2></com2> </div> <script> Vue.prototype.$eventBus = new Vue() Vue.component('com1', { template:`<div>com1</div>`, created () { conse.log('創(chuàng)建com1') this.$eventBus.$on('event1', function f1(d) { conse.log(d, 'com1 listen... event1') }) } }) Vue.component('com2', { template:`<div>com2</div>`, created () { this.$eventBus.$on('event2', function f2(d) { conse.log(d, 'com2 listen... event2') }) } }) var vm = new Vue({ el: '#app', data:{ showCom1: true }, created () { setInterval( () => { const d = Date.now() this.$eventBus.$emit('event1', d) this.$eventBus.$emit('event2', d) }, 3000) } }) </script>
先提一個(gè)問(wèn)題:你覺(jué)得com1組件被銷(xiāo)毀后,它在created中訂閱的event1事件還能再收到嗎?對(duì)應(yīng)的回調(diào)函數(shù)還能再執(zhí)行嗎?一般的想法是組件都銷(xiāo)毀了,那它訂閱的事件肯定也收不到了嘛
。
答案是:還能收到。原因很簡(jiǎn)單:事件訂閱這功能是$eventBus對(duì)象完成的,與這個(gè)com1組件無(wú)關(guān)。
上面的代碼執(zhí)行的效果,是這樣的:
銷(xiāo)毀組件1之后,它還能正常收到event1事件,并執(zhí)行回調(diào);
再次創(chuàng)建組件1后,它會(huì)再次訂閱event1事件,所以結(jié)果是執(zhí)行兩次回調(diào)。
下面再來(lái)說(shuō)明內(nèi)存泄漏的問(wèn)題,把com1的組件內(nèi)容改成如下:
Vue.component('com1', { template:`<div>com1</div>`, created () { console.log('創(chuàng)建com1') let m = 1*1024 * 1024 let arr = new Array(m).fill('a') this.$eventBus.$on('event1', function f1(d) { // 注意這里有一個(gè)閉包 console.log(d, 'com1 listen... event1', arr[1]) }) } })
在回調(diào)函數(shù)f1中引用函數(shù)之外的變量arr,這里有一個(gè)閉包。
下面在瀏覽器的調(diào)試工具中的memory添加一個(gè)快照,查看結(jié)果如下:
然后,點(diǎn)擊頁(yè)面上的“銷(xiāo)毀組件1”,再次添加一個(gè)快照,你會(huì)發(fā)現(xiàn)這個(gè)空間并沒(méi)有釋放掉。
解釋如下:
上面是這個(gè)過(guò)程的示意圖,由于沒(méi)有及時(shí)取消訂閱f1,所以arr這個(gè)數(shù)組并沒(méi)有釋放掉。
解決方案:
在com1的destoryed鉤子中,調(diào)用$off來(lái)取消訂閱。
destroyed () { // 取消所有對(duì)event1事件的監(jiān)聽(tīng) this.$eventBus.$off('event1') }
調(diào)試結(jié)果如下:
可見(jiàn),com1刪除之后,這個(gè)數(shù)值的空間釋放掉了,同時(shí)它的事件監(jiān)聽(tīng)函數(shù)也不會(huì)再執(zhí)行了。
$off的格式:
$off() 會(huì)取消所有的事件訂閱;
$off('事件名') 會(huì)取消指定事件名的;
$off('事件名', 回調(diào)) 會(huì)取消指定事件名的,指定回調(diào)
父子組件的created和mounted的區(qū)別, 按執(zhí)行順序:
父組件的created 先于子組件的created
父組件的mounted先于子組件的mounted
所以,到底在哪個(gè)鉤子中訂閱,在哪個(gè)鉤子中發(fā)布,要根據(jù)情況來(lái)定。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“vue中的eventBus會(huì)產(chǎn)生內(nèi)存泄漏嗎”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。