Megosztás a következőn keresztül:


ASP.NET Core Blazor JavaScript együttműködési (JS interop) teljesítményével kapcsolatos ajánlott eljárások

Megjegyzés:

Ez nem a cikk legújabb verziója. Az aktuális kiadásról a cikk .NET 10-es verziójában olvashat.

Figyelmeztetés

A ASP.NET Core ezen verziója már nem támogatott. További információt a .NET és a .NET Core támogatási szabályzatában talál. A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .

A .NET és a JavaScript közötti hívások további többletterhelést igényelnek, mert:

  • A hívások aszinkronok.
  • A paraméterek és a visszatérési értékek JSON-szerializáltak, hogy könnyen érthető konverziós mechanizmust biztosítsanak a .NET és a JavaScript-típusok között.

A kiszolgálóoldali Blazor-alkalmazások esetében ezek a hívások a hálózaton keresztül is továbbítva lesznek.

Kerülje a túlzottan részletes hívásokat

Mivel minden hívás némi többletterheléssel jár, érdemes lehet csökkenteni a hívások számát. Vegye figyelembe a következő kódot, amely a böngészőben localStoragetárolja az elemek gyűjteményét.

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

Az előző példa minden elemhez külön JS interop-hívást készít. Ehelyett a következő megközelítés egyetlen hívásra csökkenti a JS interop-t:

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

A megfelelő JavaScript-függvény az ügyfélen tárolja az elemek teljes gyűjteményét:

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

Az Blazor WebAssembly alkalmazások esetében az egyes JS interop-hívások egyetlen hívásba való indítása általában csak akkor javítja jelentősen a teljesítményt, ha az összetevő nagy számú JS interop-hívást indít.

Fontolja meg a szinkron hívások használatát

JavaScript hívása a .NET-ből

Ez a szakasz csak az ügyféloldali összetevőkre vonatkozik.

A JS interop hívások aszinkron módon történnek, függetlenül attól, hogy a hívott kód szinkron vagy aszinkron. A hívások aszinkron módon biztosítják, hogy az összetevők kompatibilisek legyenek a kiszolgálóoldali és az ügyféloldali renderelési módok között. A kiszolgálón minden JS interop-hívásnak aszinkronnak kell lennie, mert hálózati kapcsolaton keresztül küldi őket.

Ha biztosan tudja, hogy az összetevő csak a WebAssemblyen fut, választhat, hogy szinkron JS interop-hívásokat kezdeményez. Ez valamivel kisebb többletterheléssel jár, mint az aszinkron hívások végrehajtása, és kevesebb renderelési ciklust eredményezhet, mivel nincs köztes állapot az eredményekre várva.

Ha egy ügyféloldali összetevőben .NET-ről JavaScriptre szinkron hívást szeretne végrehajtani, a IJSRuntime interop-hívás elindításához alakítsa át IJSInProcessRuntime-t JS-re.

@inject IJSRuntime JS

...

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

A .NET 5-ös vagy újabb ügyféloldali összetevőinek IJSObjectReference használatakor használhatja szinkron módon IJSInProcessObjectReference is. IJSInProcessObjectReference megvalósítja a IAsyncDisposable/IDisposable-at, és a memóriaszivárgás elkerülése érdekében át kell adni a szemétgyűjtésnek, ahogy az alábbi példa mutatja:

@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();
        }
    }
}

Az előző példában egy JSDisconnectedException nem csapódott be a modul eltávolítása során, mert nincs Blazor–SignalR áramkör, amit egy Blazor WebAssembly alkalmazásnál elveszíthetne. További információ: ASP.NET Core Blazor JavaScript-együttműködés (JS interop).

.NET hívása JavaScriptből

Ez a szakasz csak az ügyféloldali összetevőkre vonatkozik.

A JS interop hívások aszinkron módon történnek, függetlenül attól, hogy a hívott kód szinkron vagy aszinkron. A hívások aszinkron módon biztosítják, hogy az összetevők kompatibilisek legyenek a kiszolgálóoldali és az ügyféloldali renderelési módok között. A kiszolgálón minden JS interop-hívásnak aszinkronnak kell lennie, mert hálózati kapcsolaton keresztül küldi őket.

Ha biztosan tudja, hogy az összetevő csak a WebAssemblyen fut, választhat, hogy szinkron JS interop-hívásokat kezdeményez. Ez valamivel kisebb többletterheléssel jár, mint az aszinkron hívások végrehajtása, és kevesebb renderelési ciklust eredményezhet, mivel nincs köztes állapot az eredményekre várva.

Ha egy ügyféloldali összetevőben a JavaScriptből a .NET-be szeretne szinkron hívást kezdeményezni, használja DotNet.invokeMethod a DotNet.invokeMethodAsynchelyett.

A szinkron hívások akkor működnek, ha:

  • Az összetevő csak a WebAssemblyben való végrehajtáshoz lesz renderelve.
  • A hívott függvény szinkron módon ad vissza egy értéket. A függvény nem async metódus, és nem ad vissza .NET-Task vagy JavaScript-Promise.

Ez a szakasz csak az ügyféloldali összetevőkre vonatkozik.

A JS interop hívások aszinkron módon történnek, függetlenül attól, hogy a hívott kód szinkron vagy aszinkron. A hívások aszinkron módon biztosítják, hogy az összetevők kompatibilisek legyenek a kiszolgálóoldali és az ügyféloldali renderelési módok között. A kiszolgálón minden JS interop-hívásnak aszinkronnak kell lennie, mert hálózati kapcsolaton keresztül küldi őket.

Ha biztosan tudja, hogy az összetevő csak a WebAssemblyen fut, választhat, hogy szinkron JS interop-hívásokat kezdeményez. Ez valamivel kisebb többletterheléssel jár, mint az aszinkron hívások végrehajtása, és kevesebb renderelési ciklust eredményezhet, mivel nincs köztes állapot az eredményekre várva.

Ha egy ügyféloldali összetevőben .NET-ről JavaScriptre szinkron hívást szeretne végrehajtani, a IJSRuntime interop-hívás elindításához alakítsa át IJSInProcessRuntime-t JS-re.

@inject IJSRuntime JS

...

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

A .NET 5-ös vagy újabb ügyféloldali összetevőinek IJSObjectReference használatakor használhatja szinkron módon IJSInProcessObjectReference is. IJSInProcessObjectReference megvalósítja a IAsyncDisposable/IDisposable-at, és a memóriaszivárgás elkerülése érdekében át kell adni a szemétgyűjtésnek, ahogy az alábbi példa mutatja:

@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();
        }
    }
}

Az előző példában egy JSDisconnectedException nem csapódott be a modul eltávolítása során, mert nincs Blazor–SignalR áramkör, amit egy Blazor WebAssembly alkalmazásnál elveszíthetne. További információ: ASP.NET Core Blazor JavaScript-együttműködés (JS interop).

Fontolja meg a nem felügyelt hívások használatát

Ez a szakasz csak Blazor WebAssembly alkalmazásokra vonatkozik.

Ha a Blazor WebAssembly fut, a .NET-ről JavaScriptre irányuló nem csomagolt hívásokat is kezdeményezhet. Ezek szinkron hívások, amelyek nem hajtják végre az argumentumok JSON-szerializálását, és nem adnak vissza értékeket. A memóriakezelés és a .NET és JavaScript-reprezentációk közötti fordítások minden aspektusa a fejlesztőre marad.

Figyelmeztetés

Bár a IJSUnmarshalledRuntime használata a legkisebb többletterheléssel jár az JS interop megközelítések esetében, az ezen API-k használatához szükséges JavaScript API-k jelenleg nem dokumentálva vannak, és a jövőbeli kiadásokban kompatibilitástörő változásoknak vannak kitéve.

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

[JSImport] / [JSExport] JavaScript-interop használata

A JavaScript [JSImport]/[JSExport]Blazor WebAssembly alkalmazásokhoz készült interop jobb teljesítményt és stabilitást biztosít az JS interop API-val szemben az ASP.NET Core előtti .NET 7 keretrendszer kiadásaiban.

További információért lásd: JavaScript JSImport/JSExport interop ASP.NET Core-val Blazor.