Answer the question
In order to leave comments, you need to log in
How to detect and fix a memory leak in an interface?
Given:
Composite component for customizing the number replacement on the page.
There are 2 columns:
1 - settings
2 - number replacement visualizer
What's going on?
The user changes the visualization settings (they are quite decent - there is a css customizer and a number replacement mask and display with the prefix location, changing the prefix text, displaying in the modal, changing the content of the modal) - the settings redraw the visualizer when changed.
What is most interesting is the mask setting - selects that contain static markup. The markup of the selected select is dropped into the renderer and rendered via v-html. It is, of course, not reactive, and the renderer methods that customize the display of the mask pick it directly through the DOM.
What's wrong?
If you open the tab and set everything up at once, everything is fine. If you leave the settings tab for a couple of hours (even a couple of tens of minutes), the tab dies. If you open devtools, all of its tools will lag and hang mercilessly. This can be traced far from the iron and in all browsers.
What was I trying to do?
Previously, the visualizer was redrawn via watch. That is, data with settings fell into the component through props, and these props were tracked in the visualizer. I removed all the watchers and replaced them with emitters. That is, when changing a setting, the component of this setting calls the method described in the main component of the section. In this method, the components are searched and when a visualizer is found, it is emitted with the desired method, depending on the settings.
Additionally, I put timeouts on all input fields, which can cause emits too often. It became a little easier, but still the leak remained and the tab was dull. How can you optimize more?
A bit of code: methods of the main component of the parent that emit the renderer when the settings are changed:
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()
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question