Sdílet prostřednictvím


osvědčené postupy z hlediska výkonuBlazor ASP.NET Core JS JavaScript (interoperabilita)

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 10 tohoto článku.

Výstraha

Tato verze ASP.NET Core již není podporována. Pro více informací se podívejte na Zásady podpory .NET a .NET Core. Aktuální vydání tohoto článku najdete v verzi .NET 9.

Volání mezi .NET a JavaScriptem vyžadují další režii, protože:

  • Volání jsou asynchronní.
  • Parametry a návratové hodnoty jsou serializované ve formátu JSON, aby poskytovaly snadno pochopitelný mechanismus převodu mezi typy .NET a JavaScript.

Kromě toho pro aplikace na straně Blazor serveru se tato volání předávají přes síť.

Vyhněte se příliš jemně odstupňovaným voláním

Vzhledem k tomu, že každé volání zahrnuje určité režijní náklady, může být užitečné snížit počet hovorů. Vezměte v úvahu následující kód, který ukládá kolekci položek v prohlížeči localStorage:

private async Task StoreAllInLocalStorage(IEnumerable<TodoItem> items)
{
    foreach (var item in items)
    {
        await JS.InvokeVoidAsync("localStorage.setItem", item.Id, 
            JsonSerializer.Serialize(item));
    }
}

Předchozí příklad vytvoří samostatné JS volání vzájemné spolupráce pro každou položku. Místo toho následující přístup snižuje interoperabilitu JS na jedno volání:

private async Task StoreAllInLocalStorage(IEnumerable<TodoItem> items)
{
    await JS.InvokeVoidAsync("storeAllInLocalStorage", items);
}

Odpovídající funkce JavaScriptu ukládá celou kolekci položek v klientovi:

function storeAllInLocalStorage(items) {
  items.forEach(item => {
    localStorage.setItem(item.id, JSON.stringify(item));
  });
}

U Blazor WebAssembly aplikací se postupné volání jednotlivých JS zprostředkovatele komunikace do jednoho volání obvykle výrazně zvyšuje výkon pouze v případě, že komponenta provádí velký počet JS volání zprostředkovatele komunikace.

Zvažte použití synchronních volání.

Volání JavaScriptu z .NET

Tato část se týká pouze komponent na straně klienta.

JS interop volání jsou asynchronní, bez ohledu na to, zda je volaný kód synchronní nebo asynchronní. Volání jsou asynchronní, aby se zajistilo, že komponenty jsou kompatibilní napříč režimy vykreslování na straně serveru a na straně klienta. Na serveru musí být všechna JS mezioperační volání asynchronní, protože se odesílají přes síťové připojení.

Pokud víte, že vaše komponenta běží jenom na WebAssembly, můžete se rozhodnout provádět synchronní JS volání interopu. To má o něco menší režii než provádění asynchronních volání a může vést k menšímu počtu cyklů vykreslování, protože při čekání na výsledky neexistuje žádný přechodný stav.

Pokud chcete v komponentě na straně klienta provést synchronní volání z .NET do JavaScriptu, přetypujte IJSRuntime na IJSInProcessRuntime pro provedení volání pro mezijazykovou spolupráci JS.

@inject IJSRuntime JS

...

@code {
    protected override void HandleSomeEvent()
    {
        var jsInProcess = (IJSInProcessRuntime)JS;
        var value = jsInProcess.Invoke<string>("javascriptFunctionIdentifier");
    }
}

Při práci s IJSObjectReference komponentami na straně klienta .NET 5 nebo novějším můžete místo toho použít IJSInProcessObjectReference synchronně. IJSInProcessObjectReference implementuje IAsyncDisposable/IDisposable a musí být uvolněna ke garbage collection, aby se zabránilo úniku paměti, jak ukazuje následující příklad:

@inject IJSRuntime JS
@implements IDisposable

...

@code {
    ...
    private IJSInProcessObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var jsInProcess = (IJSInProcessRuntime)JS;
            module = await jsInProcess.Invoke<IJSInProcessObjectReference>("import", 
                "./scripts.js");
            var value = module.Invoke<string>("javascriptFunctionIdentifier");
        }
    }

    ...

    void IDisposable.Dispose()
    {
        if (module is not null)
        {
            await module.Dispose();
        }
    }
}

V předchozím příkladu JSDisconnectedException není při vyřazení modulu zachycený, protože v Blazor aplikaci není žádný SignalR-Blazor WebAssembly okruh, který by se ztratil. Další informace najdete v tématu ASP.NET Core Blazor interoperabilita JavaScriptu (JSinterop).

Volání .NET z JavaScriptu

Tato část se týká pouze komponent na straně klienta.

JS interop volání jsou asynchronní, bez ohledu na to, zda je volaný kód synchronní nebo asynchronní. Volání jsou asynchronní, aby se zajistilo, že komponenty jsou kompatibilní napříč režimy vykreslování na straně serveru a na straně klienta. Na serveru musí být všechna JS mezioperační volání asynchronní, protože se odesílají přes síťové připojení.

Pokud víte, že vaše komponenta běží jenom na WebAssembly, můžete se rozhodnout provádět synchronní JS volání interopu. To má o něco menší režii než provádění asynchronních volání a může vést k menšímu počtu cyklů vykreslování, protože při čekání na výsledky neexistuje žádný přechodný stav.

Pokud chcete v komponentě na straně klienta provést synchronní volání z JavaScriptu do .NET, použijte DotNet.invokeMethod místo DotNet.invokeMethodAsync.

Synchronní volání fungují v následujících případech:

  • Komponenta se vykreslí pouze pro provádění ve službě WebAssembly.
  • Volaná funkce vrátí synchronně hodnotu. Funkce není async metoda a nevrací .NET Task ani JavaScript Promise.

Tato část se týká pouze komponent na straně klienta.

JS interop volání jsou asynchronní, bez ohledu na to, zda je volaný kód synchronní nebo asynchronní. Volání jsou asynchronní, aby se zajistilo, že komponenty jsou kompatibilní napříč režimy vykreslování na straně serveru a na straně klienta. Na serveru musí být všechna JS mezioperační volání asynchronní, protože se odesílají přes síťové připojení.

Pokud víte, že vaše komponenta běží jenom na WebAssembly, můžete se rozhodnout provádět synchronní JS volání interopu. To má o něco menší režii než provádění asynchronních volání a může vést k menšímu počtu cyklů vykreslování, protože při čekání na výsledky neexistuje žádný přechodný stav.

Pokud chcete v komponentě na straně klienta provést synchronní volání z .NET do JavaScriptu, přetypujte IJSRuntime na IJSInProcessRuntime pro provedení volání pro mezijazykovou spolupráci JS.

@inject IJSRuntime JS

...

@code {
    protected override void HandleSomeEvent()
    {
        var jsInProcess = (IJSInProcessRuntime)JS;
        var value = jsInProcess.Invoke<string>("javascriptFunctionIdentifier");
    }
}

Při práci s IJSObjectReference komponentami na straně klienta .NET 5 nebo novějším můžete místo toho použít IJSInProcessObjectReference synchronně. IJSInProcessObjectReference implementuje IAsyncDisposable/IDisposable a musí být uvolněna ke garbage collection, aby se zabránilo úniku paměti, jak ukazuje následující příklad:

@inject IJSRuntime JS
@implements IDisposable

...

@code {
    ...
    private IJSInProcessObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var jsInProcess = (IJSInProcessRuntime)JS;
            module = await jsInProcess.Invoke<IJSInProcessObjectReference>("import", 
                "./scripts.js");
            var value = module.Invoke<string>("javascriptFunctionIdentifier");
        }
    }

    ...

    void IDisposable.Dispose()
    {
        if (module is not null)
        {
            await module.Dispose();
        }
    }
}

V předchozím příkladu JSDisconnectedException není při vyřazení modulu zachycený, protože v Blazor aplikaci není žádný SignalR-Blazor WebAssembly okruh, který by se ztratil. Další informace najdete v tématu ASP.NET Core Blazor interoperabilita JavaScriptu (JSinterop).

Zvažte použití nepotřebných volání.

Tato část platí jenom pro Blazor WebAssembly aplikace.

Při spuštění Blazor WebAssemblyje možné provádět neoznačené volání z .NET do JavaScriptu. Jedná se o synchronní volání, která neprovádějí serializaci argumentů json ani návratových hodnot. Všechny aspekty správy a překladů paměti mezi reprezentací .NET a JavaScriptem zůstanou na vývojáři.

Výstraha

IJSUnmarshalledRuntime Používání má sice nejnižší režii přístupů JS k vzájemné spolupráci, ale rozhraní JAVAScript API potřebná k interakci s těmito rozhraními API jsou v současné době nezdokumentovaná a v budoucích verzích podléhají zásadním změnám.

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");
    }
}

Použití zprostředkovatele komunikace JavaScriptu [JSImport]/[JSExport]

Interoperabilita JavaScriptu [JSImport]/[JSExport]pro Blazor WebAssembly aplikace nabízí lepší výkon a stabilitu rozhraní API pro interoperabilitu JS v verzích rozhraní před ASP.NET Core v .NET 7.

Další informace naleznete v sekci JavaScript JSImport/JSExport interop s ASP.NET Core Blazor.