Open legistek opened 3 years ago
Thanks for contacting us, @legistek. Also, it's great to see that you've put a lot of thought into it. Most of our team members are out for the rest of the year so there will be some delay in responding to you. But we will get back to our normal schedule from early January. Just wanted to set expectations.
Happy Holidays!
Thanks for contacting us.
We're moving this issue to the Next sprint planning
milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
Is your feature request related to a problem? Please describe.
The underlying problem is rendering performance.
The specific problem is that if a complex component needs to render frequently, I have no way to specify which parts of the render tree are clean or dirty other than to sub-divide into more components.
BuildRenderTree
is an all or nothing endeavor. If I selectively skip non-dirty elements, they wind up getting removed from the DOM. If the stuff I want to skip winds up being expensive, I'm out of luck.The diff mechanism is great for preventing unneded DOM updates, but what about preventing unneeded diff evaluations in the first place? This is worst when it comes to string comparisons. We know strings are one of the biggest bottlenecks in interpreted WASM. Minimizing string comparisons I've found is one of the best way to squeeze more performance out of Blazor.
Describe the solution you'd like
I think there's a very simple solution: provide a way to tell
RenderTreeBuilder
to ignore a range of sequence numbers that were there in a previous render and should not be removed but just be left alone.Since I use code for most of my rendering at the component library level, I wouldn't personally need a Razor-way of doing this. But you could probably create a special tag like
@ignoreif([expression])
that would have the same effect; after the first render, ifexpression
were true, anything in the@ignoreif
block would just get completely left alone during diff/render.What it comes down to is, sometimes I know better than Blazor when stuff can be left alone.
Additional context
Just some code-based examples of what I'm talking about:
Suppose I have a simple input control with a label on top:
So here, I know when
Label
has actually changed. What I'd love to be able to do is say:By doing this I would not only skip execution of 3 lines of code, but more significantly I would prevent Blazor from having to compare the current value of
Label
with what was rendered previously.This is obviously a highly simplistic example. The real life application here is that I'm working on a
DataGrid
using my own derivative of the built inVirtualize
component and trying to squeeze every last bit of performance out of it that I can. I know which items are going in and out of view each time there's a render. I want to avoid doing anything to the items that aren't new.Each item is a
DataGridRow
. TheDataGridRow
instances for the items who were there on the last render are not dirty. Their individualBuildRenderTree
methods won't get called because I overrideShouldRender
. But I want to take it a step further. I don't even want to go through the 15 or so lines of code it takes to set up aDataGridRow
's relevant attributes inside the mainfor
loop when I know none of them have changed.Note I am using
SetKey
, and that's why the individualDataGridRow
' instances get recycled during scrolling. That works well, but it's not enough. It's still cycling through every visible row (whether it was there previously or not), setting all its attributes to the same values every time there's a render. If setting those attributes is at all expensive (and I'm trying to make an MVVM framework with databinding, so sometimes it can be), I'm in trouble.So what I'd like to be able to do in my main
for
loop that renders the visible rows is this:What else I've tried
So I thought this might be somewhat related to this closed issue: https://github.com/dotnet/aspnetcore/issues/16057, but the solution there mentioned by @SteveSandersonMS was to factor out into individual components. Again, though, while this prevents the individual items'
BuildRenderTree
's from getting called, you can't avoid unnecessarily reinitializing every row with its input parameters in the mainfor
loop.Another reason I think this would improve performance is that it actually avoids the need to use
SetKey
to preserve the relationship between theComponent
instance and the data item. I'm guessing that when you useSetKey
, Blazor is looking in some dictionary to try to find an existingComponent
instance to potentially recycle. That is not going to be a cost-free operation especially with large item sets. If you gave me control over the diffing, though, we wouldn't have to worry about Blazor not knowing whether to make a newComponent
or not because it would just skip the render fragments that I tell it to skip.(I will separately ask you to give me a way to control the lifecycle and re-use of
Component
instances, but one thing at a time ;))Hope this all makes sense, and is feasible.
Many thanks.