ShadowOfCasper
@ShadowOfCasper
Middle User Interface Web Developer

Как обнаружить и устранить утечку памяти в интерфейсе?

Дано:
Сложносоставной компонент кастомизации замены номера на странице.
Есть 2 колонки:
1 - настройки
2 - визуализатор замены номера

Что происходит?
Юзер меняет настройки визуализации (их прям прилично - есть и кастомизатор css и маска замены номера и отображение с расположением префикса, изменение текста префикса, отображение в модалке, изменение контента модалки) - настройки при изменении перерисовывают визуализатор.
Что самое интресное - настрока маски - селекты, в которых содержится статическая разметка. Разметка выбранного селекта падает в визуализатор и рендерится через v-html. Она, естесн, не реактивна, и методы визуализатора, кастомизирующие отображение маски ковыряют её напрямую через DOM.
Что не так?
Если открыть вкладку и всё сразу настроить - всё хорошо. Если оставить вкладку с настройками на пару часов (даже пару десятков минут) - вкладка умирает. Если открыть devtools, весь его инструментарий будет беспощадно лагать и виснуть. Подобное прослеживается далеко не на утюге и во всех браузерах.

Что я пытался сделать?
Ранее визуализатор перерисовывался через watch. То есть в компонент падали данные с настройками через props и эти пропсы отслеживались в визуализаторе. Я убрал все вотчеры и заменил их на эмиттеры. То есть при изменении настройки компонент этой настройки вызывает метод, описанный в основном компоненте раздела. В этом методе происходит поиск по компонентам и при нахождении визуализатора он эмитится с нужным методом в зависимости от настройки.
Дополнительно я поставил таймауты на все поля ввода, которые могут вызывать эмиты слишком часто. Стало чуть легче, но всё равно утечка осталась и вкладка тупит. Как можно оптимизировать ещё?

Немного кода: методы основного компонента родителя, эмитящие визуализатор при изменении настроек:
emitVisualPrefix: ->
				that = @
				if watchTimer
					clearTimeout(watchTimer)
				else 
					watchTimer = setTimeout(
						->
							that.$children.forEach (child) ->
								if child.$options.name == 'visualizer'
									child.$emit('initPrefixSettings')
					,200)

			emitInlinePrefix: ->
				that = @
				if watchTimer
					clearTimeout(watchTimer)
				else 
					watchTimer = setTimeout(
						->
							that.$children.forEach (child) ->
								if child.$options.name == 'visualizer'
									child.$emit('setInlinePrefix')
					,200)

			emitPositionPrefix: ->
				that = @
				if watchTimer
					clearTimeout(watchTimer)
				else 
					watchTimer = setTimeout(
						->
							that.$children.forEach (child) ->
								if child.$options.name == 'visualizer'
									child.$emit('setPositionPrefix')
					,200)


Инициализация методов перерисовки статической разметки в визуализаторе выглядит вот так:
methods:
			initSettings: ->
				console.log('initSettings')
				@setInlineStyles('init')
				if @settings.coverTip.enabled
					@setInlinePrefix()
					@setPositionPrefix()
		mounted: ->
			@initSettings()

			@$on 'setStyle', (type) ->
				console.log('setStyle')
				switch type
					when 'inline'
						@setInlineStyles()

			@$on 'initPrefixSettings', ->
				console.log('initPrefixSettings')
				@setInlinePrefix()
				@setPositionPrefix()

			@$on 'setInlinePrefix', ->
				console.log('setInlinePrefix')
				@setInlinePrefix()

			@$on 'setPositionPrefix', ->
				console.log('setPositionPrefix')
				@setPositionPrefix()


Что самое интересное - если initSettings() отменить, всё резко отвисает и утечка прекращается. Но без этого метода визуализатор не в состоянии применить настройки, прилетевшие с сервера
  • Вопрос задан
  • 126 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы