Fix memory leaks in dashboard: clear iframe src on dialog close, limit toast queue, add cleanup destroy method

This commit is contained in:
mahdahar 2026-03-05 16:18:43 +07:00
parent a65feb0495
commit 1ea1fd4d0e
2 changed files with 44 additions and 2 deletions

View File

@ -61,7 +61,7 @@ class Filters extends BaseFilters
'after' => [ 'after' => [
'pagecache', // Web Page Caching 'pagecache', // Web Page Caching
'performance', // Performance Metrics 'performance', // Performance Metrics
'toolbar', // Debug Toolbar #'toolbar', // Debug Toolbar
], ],
]; ];

View File

@ -7,6 +7,10 @@ document.addEventListener('alpine:init', () => {
isLoading: false, isLoading: false,
counters: { Pend: 0, Coll: 0, Recv: 0, Inc: 0, Fin: 0, Total: 0 }, counters: { Pend: 0, Coll: 0, Recv: 0, Inc: 0, Fin: 0, Total: 0 },
// Toast queue to prevent DOM accumulation
_toastQueue: [],
_maxToasts: 3,
selectedPrinter: localStorage.getItem('selectedPrinter') || 'zebracs2', selectedPrinter: localStorage.getItem('selectedPrinter') || 'zebracs2',
initSelectedPrinter() { initSelectedPrinter() {
@ -224,6 +228,7 @@ document.addEventListener('alpine:init', () => {
closeSampleDialog() { closeSampleDialog() {
this.isDialogSampleOpen = false; this.isDialogSampleOpen = false;
this.item = null; this.item = null;
this.item = [];
}, },
fetchItem(accessnumber) { fetchItem(accessnumber) {
@ -489,6 +494,9 @@ document.addEventListener('alpine:init', () => {
this.previewItem = null; this.previewItem = null;
this.previewAccessnumber = null; this.previewAccessnumber = null;
this.isPreviewIframeLoaded = false; this.isPreviewIframeLoaded = false;
// Clear iframe src to release memory
const iframe = this.$refs.previewIframe;
if (iframe) iframe.src = 'about:blank';
}, },
getPreviewUrl() { getPreviewUrl() {
if(this.previewAccessnumber != null) { if(this.previewAccessnumber != null) {
@ -563,6 +571,9 @@ document.addEventListener('alpine:init', () => {
this.engResultItem = null; this.engResultItem = null;
this.isEngResultIframeLoaded = false; this.isEngResultIframeLoaded = false;
this.isCreatingEngResult = false; this.isCreatingEngResult = false;
// Clear iframe src to release memory
const iframe = this.$refs.engResultIframe;
if (iframe) iframe.src = 'about:blank';
}, },
getEngResultUrl() { getEngResultUrl() {
@ -602,11 +613,42 @@ document.addEventListener('alpine:init', () => {
}, },
showToast(message, type = 'success') { showToast(message, type = 'success') {
// Limit concurrent toasts to prevent DOM accumulation
if (this._toastQueue.length >= this._maxToasts) {
const oldToast = this._toastQueue.shift();
if (oldToast && oldToast.parentNode) oldToast.remove();
}
const toast = document.createElement('div'); const toast = document.createElement('div');
toast.className = `alert alert-${type} fixed top-4 right-4 z-50`; toast.className = `alert alert-${type} fixed top-4 right-4 z-50`;
toast.innerHTML = `<i class="fa ${type === 'error' ? 'fa-times-circle' : 'fa-check-circle'}"></i> ${message}`; toast.innerHTML = `<i class="fa ${type === 'error' ? 'fa-times-circle' : 'fa-check-circle'}"></i> ${message}`;
document.body.appendChild(toast); document.body.appendChild(toast);
setTimeout(() => toast.remove(), 2000); this._toastQueue.push(toast);
setTimeout(() => {
toast.remove();
const index = this._toastQueue.indexOf(toast);
if (index > -1) this._toastQueue.splice(index, 1);
}, 2000);
},
destroy() {
// Clear large data arrays to free memory
this.list = [];
this.filtered = [];
this.sorted = [];
this.paginated = [];
this.auditData = null;
this._cachedAuditEvents = [];
this.item = null;
this.previewItem = null;
this.engResultItem = null;
// Clear any open dialogs and their iframe references
if (this.$refs.previewIframe) this.$refs.previewIframe.src = 'about:blank';
if (this.$refs.engResultIframe) this.$refs.engResultIframe.src = 'about:blank';
// Clear any remaining toasts
this._toastQueue.forEach(t => { if (t.parentNode) t.remove(); });
this._toastQueue = [];
}, },
})); }));
}); });