您好,登錄后才能下訂單哦!
如果你在用 Vue 開發應用,那么就要當心內存泄漏的問題。這個問題在單頁應用 (SPA) 中尤為重要,因為在 SPA 的設計中,用戶使用它時是不需要刷新瀏覽器的,所以 JavaScript 應用需要自行清理組件來確保垃圾回收以預期的方式生效。因此在vue開發過程中,你需要時刻警惕內存泄漏的問題,這些內存泄漏往往會發生在使用 Vue 之外的其它進行 DOM 操作的三方庫時,請確保測試應用的內存泄漏問題并在適當的時機做必要的組件清理。
下面是我開發過程中遇到,并查資料總結的內存泄漏問題,會持續更新中
一、vue自定義指令給元素綁定事件,卻沒有解綁事件
這個問題見上篇博客,vue自定義指令導致的內存泄漏問題解決
二、v-if指令產生的內存泄露
v-if也是一個容易產生內存泄漏的地方。因為:
1、v-if綁定到false的值,但是實際上dom元素在隱藏的時候沒有被真實的釋放掉
2、就是非常常見的比如我們通過v-if刪除了父級元素,但是并沒有移除父級元素里的dom片段。通常產生于使用第三方庫的時候,比如下面的示例中,我們加載了一個帶有非常多選項的選擇框,然后我們用到了一個顯示/隱藏按鈕,通過一個 v-if 指令從虛擬 DOM 中添加或移除它。這個示例的問題在于這個 v-if 指令會從 DOM 中移除父級元素,但是我們并沒有清除由 Choices.js 新添加的 DOM 片段,從而導致了內存泄漏。
<link rel="stylesheet prefetch" rel="external nofollow" > <script src="https://joshuajohnson.co.uk/Choices/assets/scripts/dist/choices.min.js?version=3.0.3"></script> <div id="app"> <button v-if="showChoices" @click="hide">Hide</button> <button v-if="!showChoices" @click="show" >Show</button> <div v-if="showChoices"> <select id="choices-single-default"></select> </div> </div>
new Vue({ el: "#app", data: function () { return { showChoices: true } }, mounted: function () { this.initializeChoices() }, methods: { initializeChoices: function () { let list = [] // 我們來為選擇框載入很多選項 // 這樣的話它會占用大量的內存 for (let i = 0; i < 1000; i++) { list.push({ label: "Item " + i, value: i }) } new Choices("#choices-single-default", { searchEnabled: true, removeItemButton: true, choices: list }) }, show: function () { this.showChoices = true this.$nextTick(() => { this.initializeChoices() }) }, hide: function () { this.showChoices = false } } })
解決實例:在上述的示例中,我們可以用 hide() 方法在將選擇框從 DOM 中移除之前做一些清理工作,來解決內存泄露問題。為了做到這一點,我們會在 Vue 實例的數據對象中保留一個屬性,并會使用 Choices API 中的 destroy() 方法將其清除。
new Vue({ el: "#app", data: function () { return { showChoices: true, choicesSelect: null } }, mounted: function () { this.initializeChoices() }, methods: { initializeChoices: function () { let list = [] for (let i = 0; i < 1000; i++) { list.push({ label: "Item " + i, value: i }) } // 在我們的 Vue 實例的數據對象中設置一個 `choicesSelect` 的引用 this.choicesSelect = new Choices("#choices-single-default", { searchEnabled: true, removeItemButton: true, choices: list }) }, show: function () { this.showChoices = true this.$nextTick(() => { this.initializeChoices() }) }, hide: function () { // 現在我們可以讓 Choices 使用這個引用 // 在從 DOM 中移除這些元素之前進行清理工作 this.choicesSelect.destroy() this.showChoices = false } } })
三、vue-router跳轉到別的組件導致的內容泄漏
在上述示例中,我們使用了一個 v-if 指令產生內存泄漏,但是一個更常見的實際的場景是使用 Vue Router 在一個單頁應用中路由到不同的組件。
就像這個 v-if 指令一樣,當一個用戶在你的應用中導航時,Vue Router 從虛擬 DOM 中移除了元素,并替換為了新的元素。但是其子元素dom片段也并沒有銷毀。
Vue 的 beforeDestroy() 生命周期鉤子是一個解決基于 Vue Router 的應用中的這類問題的好方法。我們可以將清理工作放入 beforeDestroy() 鉤子,像這樣:
beforeDestroy: function () { this.choicesSelect.destroy() }
所以最正確的解決方案就是:首先,v-if置為false前先刪除創建的dom片段;其次,路由跳出吃,在beforeDestroy鉤子函數里面判斷choicesSelect是否銷毀,沒銷毀則銷毀。
還有一個替代方案:
我們已經討論了移除元素時的內存管理,但是如果你打算在內存中保留狀態和元素該怎么做呢?這種情況下,你可以使用內建的 keep-alive 組件。
當你用 keep-alive 包裹一個組件后,它的狀態就會保留,因此就留在了內存里。
<button @click="show = false">Hide</button> <keep-alive> // <my-component> 即便被刪除仍會刻意保留在內存里 <my-component v-if="show"></my-component> </keep-alive>
這個技巧可以用來提升用戶體驗。例如,設想一個用戶在一個文本框中輸入了評論,之后決定導航離開。如果這個用戶之后導航回來,那些評論應該還保留著。
一旦你使用了 keep-alive,那么你就可以訪問另外兩個生命周期鉤子:activated和 deactivated。如果你想要在一個 keep-alive 組件被移除的時候進行清理或改變數據,可以使用 deactivated 鉤子。
deactivated: function () { // 移除任何你不想保留的數據,或者銷毀可能產生內存泄漏的地方 }
以上這篇Vue優化:常見會導致內存泄漏問題及優化詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。