Blazor Performance

Limit Frequent Events

Your browser needs to be JavaScript capable to view this video

Try reloading this page, or reviewing your browser settings

Some browser events trigger extremely frequently, such as onmousemove. By reducing the number of times these events trigger you can greatly reduce the amount of work performed by your event handlers.

Keywords

  • Events
  • JavaScript Interop
  • Optimize event handling
  • Asynchronous calls

About this video

Author(s)
Peter Himschoot
First online
24 April 2021
DOI
https://doi.org/10.1007/978-1-4842-6977-0_8
Online ISBN
978-1-4842-6977-0
Publisher
Apress
Copyright information
© Peter Himschoot 2021

Video Transcript

In this segment of the video, we’re going to look at how we can limit frequent events to avoid massive re-rendering. We’re going to talk about what is the problem with frequent events, and then we’re going to look at how we can throttle events in Blazor.

In Blazor, we can have our components react to events. Each time this happens, the component will invoke the designated event handler and then render itself. Some events like mousemove trigger tens or a 100 times per second.

In this case, the sheer number of events will give your component a lot of work. It might result in a slow UI. In this case, you can replace the normal event handling with throttled or the bounced events, reducing the number of events drastically.

Let us start with an example. So here, I have an application which uses a canvas, and as I move my mouse around, it draws a little line. And as you can see below here, we’re getting a lot of events.

In a second, we can easily get tens of events. Let me show you the code a bit.

I have a demo component, which uses a canvas, using the Excubo Blazor Canvas library. And then, I have a mousemove event handler. And as I move my mouse, I’m doing the drawing on the canvas.

So how can we limit the number of events at the source? Since you don’t want Blazor to handle the mousemove event, we’ll start by removing the handler.

We will handle the mousemove using JS interop. So I will use the IJS runtime instance.

So now, we need to add a DotNetObjectReference, so we can invoke a method from JavaScript on the component. We need to initialize this self-reference. I will do that in the OnAfterRenderAsync lifetime method.

When this event triggers, we will make our JavaScript call an event handler. This event handler is very similar to the old mousemove method, so we can copy most of it.

I’m. Just going to make a copy. I’m going to rename these. It is also very important that we add the JS invocable attribute to this method. This way, JavaScript interop can call this method from JavaScript.

Finally, I’m going to call this throttled mousemove. So now, we are ready for the JavaScript stuff. We will add an event handler for the mousemove event ourselves.

So let me open up in exit HTML. And the first thing that I want to do is I need a library that will help me to throttle events. And there are several choices, but I have decided to go for lodash.

We can find lodash on this URL. And here, we can now download the script. So I’m going to copy the script back to the clipboard. And I’m going to go back, and I’m going to add it to my index of HTML.

Please note that I picked a version with integrity checking on. Again, this helps against attacks. Now, we can add the script to attach the mousemove event handler.

The first argument is the elements from the Blazor component, where we want to register the event. So I will use addEventListener to add the mousemove event.

For the mousemove event handler itself, we will use lodash. So I’m going to replace the ellipsis with a call to lodash, passing in the handler and the interval argument.

The handler will invoke our throttled mousemove method on the component using Blazor JavaScript interop.

Let’s go back to our component, back to C#. When a component has been rendered, we need to invoke the unthrottled mousemove JavaScript method to attach the event handler to the element.

And again, we’re going to do that in the OnAfterRenderAsync method. Now, I’m going to tell the JavaScript interop to call the JavaScript method passing the canvas, the component itself, and an interval.

We also need to define this mouse interval. And this is going to be in milliseconds. And I want to have five events per second. So I’m going to make this an int of 200 milliseconds.

So let’s quickly review what we did. We created a DotNetObjectReference to the component. And then, we call this JavaScript passing in the canvas, the component, and a mouse interval. This will then install an event handler for the mousemove, which is throttled. And then, when the mousemove actually happens, we will call the throttled mousemove method on our component, passing in the mouse position.

Now, back to the component. And we see, in order to call this method, it has to have the JS invocable attribute, and it has to be a public method. So you might want to double-check if that is correct in your case.

Let’s build and run. And now, as I move my mouse around, we see we have a lot less mouse events. But there is still one little problem. This property is not updating.

So why is that? Well, the reason is simple. Our component does not receive the event itself anymore, so it will not update itself. So the solution to make this part work is to add one more thing.

So by adding StateHasChanged, I tell the component to render itself on the mouse event, and that will then update the field showing me the mouse moves. And again, let’s try. And now, we see that this field is updating, and we have a lot of those events.

Time for the summary. Don’t let Blazor handle frequent events because these will make your components re-render themselves way too many times. Instead, you can throttle them from JavaScript.

And for example, you can use the lodash library, which has this easy throttle method. By the way, I have included the URL to the CDN for lodash your convenience.

And then, from JavaScript, you can invoke a component when it’s actually required. And inside the components, you can then use StateHasChanged to make the component render itself again.