I have the following js in my electron app to resize table columns:
const resizerMouseDown = (e) => {
let th = e.target.parentNode
let startOffset = th.offsetWidth - e.x
window.addEventListener('mousemove', function (e) {
if (th) {
th.style.width = startOffset + e.x + 'px'
}
})
window.addEventListener('mouseup', function () {
th = undefined
})
}
Example Table: (Arrays from json files populate the table contents)
<table>
<thead>
<tr>
<th>
<div>Column 1</div>
<button on:mousedown={resizerMouseDown} class="resizer"></button>
</th>
<th>
<div>Column 2</div>
<button on:mousedown={resizerMouseDown} class="resizer"></button>
</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" /></td>
<td><input type="text" /></td>
</tr>
</tbody>
</table>
When the table rows are more that 100, resizing the columns are very slow. I'm not even going to mention when the json files are huge (1000+ table rows).
Any suggestions to get better performance out of the code, or would this be a limitation of electron?
Whenever the mouse moves, you're checking whether th was defined. This is not particularly efficient to do, since you only want your listeners to execute when the resizerMouseDown function was called in the first place.
To circumvent this (and to not register the same listener over and over again), I suggest to clean up the event listeners once the mouse is back up by using window.removeEventListener():
const resizerMouseDown = (e) => {
let th = e.target.parentNode
let startOffset = th.offsetWidth - e.x
const moveListener = e => {
th.style.width = startOffset + e.x + 'px'
}
const upListener = e => {
th = undefined
window.removeEventListener('mousemove', moveListener)
window.removeEventListener('mouseup', upListener)
}
window.addEventListener('mousemove', moveListener)
window.addEventListener('mouseup', upListener)
}
Also, it's worth noting that the move listener will fire whenever the browser sends the signal that the mouse moved. However, resizing the table on every move might not be very efficient and redrawing 1000+ rows over and over again is certainly heavy on the CPU and the GPU. Thus, what about adding a threshold and only resizing every 10 calls or so:
const resizerMouseDown = (e) => {
let th = e.target.parentNode
let startOffset = th.offsetWidth - e.x
var skipCount = 0
var isDirty = false
var lastXValue = 0
const resize = xValue => {
th.style.width = startOffset + xValue + 'px'
isDirty = false
}
const moveListener = e => {
skipCount++
if (skipCount >= 10) resize (e.x)
else {
lastXValue = e.x
isDirty = true
}
}
const upListener = e => {
if (isDirty) resize (lastXValue)
th = undefined
window.removeEventListener('mousemove', moveListener)
window.removeEventListener('mouseup', upListener)
}
window.addEventListener('mousemove', moveListener)
window.addEventListener('mouseup', upListener)
}
(As you can see, in case the last resize before the mouse button was up was skipped, the event listener for the mouseup event detects this and resizes the column a final time.) I suggest playing with the values, especially the skip threshold.
Aside from this, yes, resizing huge tables is slow by default. The browser will need to re-calculate the width of every single table cell and when there are many, it will slow down considerably.
One final note: I have not tested this code for its performance. This answer is based purely on general code efficiency and guesses towards performance bottlenecks. Feel free to analyse this code using Chromium's built-in profiler (also available on Electron); this will tell you exactly where you can optimise further.