Touching the DOM can obviously be a major bottleneck, so I think it might be a good idea to look into memoizing all D3 accessors for additional performance improvements. In a higher-level wrapper, I use the simple technique of using the getter of each accessor to compare with the target value and only make the change if they are different. Since D3 components are used as "stamps" this scenario is very common. That is, in subsequent renders, most modifications should already be set and so it should really amount to a noop if nothing has changed:
function component(data) {
once(this)
('li', data)
.attr('tabindex', -1)
.classed('.active', d => d.active)
.text(d => d.label)
}
I don't have comprehensive stats, but running the following quick tests shows that resetting a property to it's own value is not completely trivial - ~0.2ms vs 0ms (setTimeout
is used to avoid compiler loop invariant optimisations):
for (var i = 0; i < 100; i++) time(i*100, perf(d => input.value))
for (var i = 0; i < 100; i++) time(i*100, perf(d => input.value = 'foo'))
Open a new tab, open the console, and paste the following in the address bar to run:
data:text/html, <head><script src="https://rawgit.com/utilise/utilise/master/utilise.js"></script><body><input><script>input = raw('input'); for (var i = 0; i < 100; i++) time(i*100, perf(d => input.value))</script>
data:text/html, <head><script src="https://rawgit.com/utilise/utilise/master/utilise.js"></script><body><input><script>input = raw('input'); for (var i = 0; i < 100; i++) time(i*100, perf(d => input.value = 'foo'))</script>
The if (current !== target)
approach should work for most accessors from what I can see, except for .style
. Just checking the current value in that case can be costly. One option would be to store all the values set in a hidden __style__
object property and then check against that. However, that may restrict interoperability (i.e. if you set inline styles another way, it may lead to unexpected results in subsequent D3 set operations). It's not common to mix different solutions though, so users may just have to be cautious of that. Or an opt-in/out parameter could be added. Or you could just leave .style
as-is, since anyone who cares about performance probably isn't setting inline styles across their application (using classes is perhaps more likely).
Happy to open a PR if you think this would be a good idea..