dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.37k stars 9.99k forks source link

[Blazor] Improve StreamRender diffing and DOM change detection #57523

Closed audacode closed 1 month ago

audacode commented 1 month ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe the problem.

.NET 10 Blazor planning: I would ask that the algorithm for StreamRender be improved to only send required DOM changes to browser; and to not send a blazor-ssr template update if no change is required.

Describe the solution you'd like

With StreamRender enabled, the current implementation will repeatedly send a blazor-ssr update to the browser, even if no changes are made to the DOM in this example below:

    protected override async Task OnInitializedAsync()
    {
        StateHasChanged();
        await Task.Yield();
        StateHasChanged();
        await Task.Yield();
        StateHasChanged();
        await Task.Yield();
    }

In the above example the rendered ssr templates will have the same content and parameters. This is extremely inefficient and not consistent with InteractiveServer or InteractiveWebAssembly where no content update will be sent to the client if there was no change to the DOM.

The second part of this request is probably obvious: Can we please improve the diffing algorithm to not send the entire rendered content of a component if only a small change needs to be patched in. Blazor is so very clever in InteractiveServer and InteractiveWebAssembly mode at diffing and patching. The current StreamRender algorithm seems to send the entire content of a component on each update in a scenario where you perform multiple asynchronous awaits in OnInitializedAsync and call StateHasChanged before each await. Surely we can improve on this for .NET 10.

Additional context

No response

javiercn commented 1 month ago

@audacode thanks for contacting us.

This is not something that we plan to do. SSR doesn't keep track of previous renders and is not able to perform diffs against those.

We also don't agree with statements like This is extremely inefficient. There's no data to back it up nor reason to think that this will result in an improvement in any relevant metric.

In general, we don't think that these optimizations will bring significant benefits in most cases. For example, when a component renders a placeholder vs rendering the actual content, the few additional divs that might be contained in the component won't make any significant difference to the page size or load time for it to be relevant.

Surely we can improve on this for .NET 10.

We can improve things that are worth improving, for that, the first thing to do is prove that there is a significant benefit in doing so, otherwise resources can be spent in other features that will have a bigger impact.

iphdav commented 1 month ago

@javiercn I will add that we are not just rendering "a few additional divs". More realistically, if a component rendered 5 KB and OnInitializedAsync had 5 awaits/StateHasChanged it would end up sending 5 x 5KB = 25 KB instead of maybe sending 6 KB with a better algorithm.

iphdav commented 1 month ago

@javiercn Here is a good example. Imagine a current blazor server component that rendered 10 KB, but was awaiting something that took 30 seconds. With Blazor InteractiveServer, inside OnInitializedAsync you could be updating some progress indicator every second that is outputting how many seconds had passed. Yes this is an extreme example, but each second you could have:

StateHasChanged();
timePassed += 1;
await Task.Delay(1000);

In Blazor Server a few hundred bytes would be sent every second.

If that component was used for SSR, it would send the whole 10 KB every second, so send 300 KB in total.

These kind of differences add complexity to the developer story (what the developer needs to understand to be successful).

dotnet-policy-service[bot] commented 1 month ago

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.