In what at this point feels like a previous life, I did far more work automating Microsoft Excel with Visual Basic for Applications or from within Windows applications than I would care to admit. In those days the rendering performance of Excel was horrible and any time work was done that would modify the visible area of a spreadsheet in any significant way (such as populating a large number of rows), developers found that a significant performance gain could be achieved by ensuring that the document was not being displayed to the user while the operation was in progress. This caused Excel to bypass the repainting of the screen and freed up the processor to do more work that produces value.
How does this apply to application development today? I spend more time than I would care to admit using Javascript and HTML to build web applications. These web applications often have rich interactive requirements that are arguably more suited to running in a native application but business drivers cause us to build them to run in a variety of web browsers with a broad range of capability and performance characteristics. Regardless of the browser, a common characteristic is that one of the most expensive operations that can be triggered is a reflow, which is when a DOM element and its children and ancestors have their layout information recalculated. Reflows occur when the browser is resized, an elements CSS class is changed, or any property that affects the layout of an element is changed and the calculations necessary to achieve a reflow can often require a lot of resources.
The need to perform actions that cause reflow and their expense should lead developers down the path of trying to find ways to ensure that their code only causes the minimum number of reflows required to achieve a desired end result, which leads us back to the “do it offscreen” model used in VBA automation. There are many ways to achieve this end with Javascript, CSS, and the DOM, but two of the easiest include using a “working copy” and toggling visibility.
For the “working copy” method, you use the cloneNode method to create a copy of the element which requires modification, manipulate that element (which at this point is not part of the DOM), and then replace the original with the modified copy. This causes all the updates made to the element to only trigger a single reflow and is illustrated in the following code:
var elementToModify = document.getElementById("myElementToModify");
var workingCopy = elementToModify.cloneNode(true);
// update display-related elements
// append children
// etc....
elementToModify.parentNode.replaceChild(workingCopy, elementToModify);
For toggling visibility, you would make the element invisible by manipulating the display property, manipulate the element, and then set it back to visible. This would cause two reflows and is illustrated in the following code:
var elementToModify = document.getElementById("myElementToModify");
elementToModify.style.display = "none";
// update display-related elements
// append children
// etc....
elementToModify.style.display = "block";
Depending on how much time it takes to perform the updates the technique changing the visibility of the element might give a “jumpy” appearance to the page, so in most situations I would opt for the “working copy” technique.
In this posting I hope to have given information that will cause you to think more about when you’re taking action in Javascript that will trigger a reflow of all or a portion of the DOM and to have also provided some tools to help you minimize the performance impact of these actions.