aspnetcore/blazor/performance/javascript-interoperability.md
Calls between .NET and JavaScript require additional overhead because:
Additionally for server-side Blazor apps, these calls are passed across the network.
Since each call involves some overhead, it can be valuable to reduce the number of calls. Consider the following code, which stores a collection of items in the browser's localStorage:
private async Task StoreAllInLocalStorage(IEnumerable<TodoItem> items)
{
foreach (var item in items)
{
await JS.InvokeVoidAsync("localStorage.setItem", item.Id,
JsonSerializer.Serialize(item));
}
}
The preceding example makes a separate JS interop call for each item. Instead, the following approach reduces the JS interop to a single call:
private async Task StoreAllInLocalStorage(IEnumerable<TodoItem> items)
{
await JS.InvokeVoidAsync("storeAllInLocalStorage", items);
}
The corresponding JavaScript function stores the whole collection of items on the client:
function storeAllInLocalStorage(items) {
items.forEach(item => {
localStorage.setItem(item.id, JSON.stringify(item));
});
}
For Blazor WebAssembly apps, rolling individual JS interop calls into a single call usually only improves performance significantly if the component makes a large number of JS interop calls.
:::moniker range=">= aspnetcore-5.0"
:::moniker-end
:::moniker range="< aspnetcore-5.0"
:::moniker-end
:::moniker range=">= aspnetcore-5.0 < aspnetcore-7.0"
This section only applies to Blazor WebAssembly apps.
When running on Blazor WebAssembly, it's possible to make unmarshalled calls from .NET to JavaScript. These are synchronous calls that don't perform JSON serialization of arguments or return values. All aspects of memory management and translations between .NET and JavaScript representations are left up to the developer.
[!WARNING] While using xref:Microsoft.JSInterop.IJSUnmarshalledRuntime has the least overhead of the JS interop approaches, the JavaScript APIs required to interact with these APIs are currently undocumented and subject to breaking changes in future releases.
function jsInteropCall() {
return BINDING.js_to_mono_obj("Hello world");
}
@inject IJSRuntime JS
@code {
protected override void OnInitialized()
{
var unmarshalledJs = (IJSUnmarshalledRuntime)JS;
var value = unmarshalledJs.InvokeUnmarshalled<string>("jsInteropCall");
}
}
:::moniker-end
:::moniker range=">= aspnetcore-7.0"
[JSImport]/[JSExport] interopJavaScript [JSImport]/[JSExport] interop for Blazor WebAssembly apps offers improved performance and stability over the JS interop API in framework releases prior to ASP.NET Core in .NET 7.
For more information, see xref:blazor/js-interop/import-export-interop.
:::moniker-end