Вот, история продолжается….

Я использую CDN-версию Vuetify для разработки своих Vue WebApps. Я создал фреймворк под названием BANanoVuetifyAD3, который представляет собой сочетание B4x + Vuetify + BANano. B4x — потрясающий язык программирования, который я люблю, и BANano транспилирует этот язык в JavaScript. Скучно правда? Неее, далеко не так.

Когда вы начнете создавать нативные приложения для Android, iOS, настольных компьютеров, Arduino и веб-приложений с помощью b4x, НА ОДНОЙ БАЗЕ КОДА, вы поймете, что я имею в виду. Это здорово.

Впрочем, вернемся к моей истории. «Анеле, у нас проблема. Я нажимал F5 в браузере, приложение в конце концов вылетает, а потребление памяти достигает 2 ГБ и более ».

"Хм!!!".

Подождите, пока вы не выполните поиск в Google по Vue Memory Leaks, и результаты поиска будут довольно удивительными. Ну вот этого я не знал. Что ж, когда я начал свое путешествие по Vue, я не сталкивался с этим. Я был взволнован, чтобы самостоятельно научиться чему-то новому, это того стоило.

Я помню, что на одном этапе у меня была проблема с полями ввода, которые были довольно медленными, как улитка. Я узнал, что грядет Vue 3 и решит эту проблему. В любом случае, со временем я также разрабатывал приложения по-другому, чтобы они работали умнее.

Во всяком случае, первое, что я решил сделать, это записывать все события жизненного цикла, которые происходили в моем приложении, чтобы я мог видеть, что происходит и, что более интересно, гдеи когда. Это мне пришлось сделать в экземпляре Vue и во всех компонентах Route.

Я сделал бу-бу, хотя. Я включил BANano.TranspilerOptions.RemoveDeadCode = True и забыл добавить 'IgnoreDeadCodeв некоторые из моих сигнатуры подпрограмм. Большая ошибка!

Это привело к тому, что такие обратные вызовы, как created, Mount, beforeDestroy и т. д., были признаны «мертвыми» транспайлером BANano, и мое приложение не работало должным образом. Код всех этих подпрограмм был «выброшен» в окончательной сборке.

Затем наступил момент глобуса, после того, как я задал довольно неловкий вопрос на форуме. Я устал, подумал я. Проверьте параметры транспилятора, сказал мой разум, сразу после того, как я нажал «Опубликовать» на форуме b4x и быстро проверил RemoveDeadCode в AppStart, это было правдой. МОЙ БОГ!!! Я даже не могу удалить этот вопрос форума больше, :(.

Это было похоже на поиски пропавшего; в JavaScript. Фу…

Итак, я запускаю консоль, записывая каждое событие жизненного цикла…

Я запускаю свое веб-приложение, и журналы работают хорошо, чтобы сообщать о том, что мне нужно.

В моей первой попытке события beforeDestroy и destroyed никогда не запускаются для экземпляра Vue. Это потому, что я не добавил прослушиватель событий для события «beforeUnload» объекта окна. Затем я обновил свой код, чтобы событие window.beforeUnload перехватывалось и запускалось, чтобы я мог выполнять в нем другие действия, например вызывать vue.$destroy.

Поэтому я реализую код для перехвата событий…

Этот код определен в подпрограмме Initialize моего класса. Когда класс инициализируется (вызывается в коде), он проверяет родительский обработчик, существуют ли такие обратные вызовы, если нет, выдает предупреждения консоли, в противном случае события добавляются к объекту окна. Что ж, код довольно самоуверен, когда дело доходит до этих трех консольных предупреждений.

Устранение утечки памяти

Таким образом, когда пользователь нажимает F5, запускается событие beforeunload, в этом случае мы можем вызвать метод vue.$destroy, который поможет GC (сборщику мусора ). Вызов .destroy гарантирует, что события beforeDestroy и destroy будут запущены для экземпляра vue, в противном случае эти события жизненного цикла вообще никогда не будут запущены. Это приводит к тому, что мусор остается в вашем браузере и приводит к сбою вашего приложения.

Так почему же мусор не вывозится?

Этот мусор возникает из-за отдельных материалов, что означает, что этот материал не существует в DOM, но на него есть ссылка где-то в приложении, поэтому он доступен в памяти. Это также могут быть события, добавленные с помощью addEventListener, таймеры и т.д., которые должны быть удалены или обнулены при уничтожении/размонтировании компонентов.

Вы можете получить к ним доступ, перейдя в DevTools › Memory и сделав снимок того, что происходит в вашем приложении. С помощью временной шкалы вы можете записывать производительность вашего приложения и видеть «синие таблетки», которые остаются в матрице. Вы не хотите этого. Выбор «синей таблетки» сообщает вам, что не «отсоединено» от матрицы (см. рис. 0 выше).

Я обнаружил, что хотя мое приложение начиналось с 64 МБ, каждый раз, когда я нажимал F5, объем памяти увеличивался, браузер зависал, а приложение аварийно завершало работу. Снова и снова.

Еще один шок…

Мои компоненты маршрута не загружаются лениво, конечно. Я просто добавляю их на VueRouter. Интересно, что когда я проверил один из отсоединенных элементов (наведите указатель мыши на элемент на 2 секунды, чтобы отобразить всплывающее окно), я обнаружил элемент (и не только), который определен в другом маршруте, а не в корневом маршруте. Эти маршруты еще не используются при запуске приложения. странный.

Хьюстон у нас проблема!

Я узнал, что также могу аннулировать $refs и object.freeze нереактивные большие массивы. Поэтому я сделал это на корневом маршруте в событии жизненного цикла beforeDestroy.

Это стало возможным из-за того, что vue.$destroy вызывается в обратном вызове window.beforeUnload, что делает beforeDestroy и destroy доступными в маршруте.

После обнуления $refs они больше не существовали в отсоединенном материале. Я улыбнулась. Я запустил свое веб-приложение, наблюдал за увеличением памяти после нажатия F5, затем сделал паузу, помните, я нажимал F5 как конец U.S.E.R (неподдерживаемый глупый элемент, (но) обязательный) — это шутка!

Я открыл диспетчер задач браузера, проверил свое приложение, уменьшился с 2G до 64 МБ, больше никаких сбоев, но стабильная работа. Задача решена.

Обновление приложений нажатием F5, особенно тех, которые интенсивно используют данные, может время от времени вызывать непреднамеренные DOS-атаки, поэтому важно иметь систему сдержек и противовесов для обнаружения запросов с одного и того же IP-адреса в минуту.

Однако я рад, что эта проблема была обнаружена моим конечным пользователем, и теперь я знаю о ней и о том, что нужно сделать, чтобы решить ее раз и навсегда.

#Счастливое кодирование Vue