Skip to content

Scenario · JS interop

JS interop

Every call below goes through the IJSRuntime injected into this component and the JS module it imports, so BevTools → JS Interop attributes it to Interop with its duration and result. JS → .NET callbacks are reported by the browser bridge. A service that calls JS itself opts in with jsRuntime.WithBevToolsTracking(session).

The calls

The functions live in wwwroot/js/interop.js: one measures the box below, one busy-waits for 400 ms, one is called 120 times in a loop, a class is constructed and its property read and written, one calls back into .NET every 200 ms, one throws, one leaves an error and a rejected promise unhandled, and one writes to localStorage and sessionStorage.

Live Renderer: Static · prerendering CtrlShiftD opens BevTools

Measured element

–
callbacks received: 0

JS Interop: per call and per identifier

The JS Interop panel counts the calls per identifier with their total, average and maximum duration and how many failed, and lists the recent calls with the component that made each one and its result. On the Server renderer every one of those calls is a round trip to the browser.

  • → marks a .NET → JS call, ← a call from JS into .NET. Start the callbacks and OnTick arrives five times a second as ←, reported by the browser bridge.
  • Calls on the imported module read module.measure, module.ping…: a module reference obtained through a tracked IJSRuntime is tracked too.
  • Create, read and write a JS object uses the .NET 10 interop members: new module.Tally, get module.count and set module.count, each a row of its own (the object came from the module, so its calls are labelled with it).
  • JS function throws is a failed call: its result is the JSException, and the identifier's Failed count goes up.

Diagnostics, Errors and Browser

  • Diagnostics: Chatty loop is excessive interop (more than 50 calls to one identifier in a second) and Slow call is slow interop (over 250 ms). The fix for both: batch the work into one JS function.
  • Errors: the JS exception the page catches (source js-interop, with the component), and the unhandled error and rejection the browser bridge reports (source javascript).
  • Browser → Read localStorage / sessionStorage after Write localStorage/sessionStorage: demo:theme and demo:cart are shown, demo:auth_token is redacted in the browser before it ever reaches .NET. The same tab shows whether the browser is online and visible, the JS heap, the page load time, and the JS errors and JS → .NET calls it counted.

Calls that are not this page's

The panel shows every tracked call in the app, so the site around this page shows up too: the search box in the header registers its keyboard shortcut once (bitDemoSite.registerPalette, from CommandPalette) and locks the page scroll while it is open (bitDemoSite.lockScroll), and the theme button calls bitDemoTheme.toggle from Header. The framework's own calls - FocusOnNavigate moving focus after each navigation - are listed as well.

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.

An unhandled error has occurred. Reload 🗙