nipplejs
nipplejs copied to clipboard
[BUG] High CPU load
Describe the bug I'm having a very high CPU load when moving the joystick around. On a high level CPU, this works fine, but in my customer's browsers, the website starts to freeze. The joystick gets stuck for some seconds, other indicators updated over a websocket have a delay of several seconds. I can also simulate it by using CPU throttling when collecting Performance metrics in Chrome.
I first figured out that my event handler function just takes too long. Therefore, I set a timeout and removed innerHTML functions. This already resulted in a much better performance on my CPU. However, I'm still having freezes on lower power CPUs.
How does manager.on() work if an event listener function takes too long to execute? Are the events just queuing up or are the same event listeners processed asynchronously? I assume the event trigger is much faster than my event listener function. How is this taken into account? Is there some measure if the events in the queue have a large time offset?
My computations in the joystick event handler are not very complex (see below).
To Reproduce Steps to reproduce the behavior:
I can't share the website or the source code. However, here's my joystick event listener:
function createJoystick() {
if (manager == null) {
joystickContainer = document.getElementById('joystick');
var options = {
zone: joystickContainer,
position: { left: '50%', top: '50%'},
mode: 'static',
size: 200,
color: '#0066ff',
restJoystick: true
};
manager = nipplejs.create(options);
}
manager.on('move', function (evt, nipple) {
if (publishImmediately2) {
publishImmediately2 = false;
var direction = nipple.angle.degree
var distance = nipple.distance;
var x_field = Math.cos(direction * pi/180)*distance/(100/max_field);
var y_advancer = Math.sin(direction * pi/180)*distance/(100/max_adv_speed);
publish(x_field, y_advancer);
setTimeout(function () {
publishImmediately2 = true;
}, 50);
}
});
manager.on('end', function () {
// Reset:
publish(0,0);
});
}
In addition, there are some indicators and an image stream on the website, which are updated over a websocket.
Expected behavior
No freezes of joystick, no delay in image stream or other elements on the website, no browser crashes, real-time control.
Screenshots, Codepen or JSFiddle

Desktop (please complete the following information):
- OS: different, Ubuntu 20.04 and Windows 10
- Browser: different, Chrome and Firefox
- Version: Chrome 94.0.4606.54, Firefox 92.0
Hey, thanks for the detailed report 🙇 I'm not sure this is actually coming from the library.
Can you try and comment these lines from your event handler and confirm that it's still struggling :
publish(x_field, y_advancer);
setTimeout(function () {
publishImmediately2 = true;
}, 50);
I can't tell what's happening in the publish function here, and it could be very heavy.
Anyway, removed the bug label, as it's not determined yet.
I think it comes from the "end" event listener. If I output console log on the end event, I get hundreds of log messages and further processing is blocked until all these events are handled. I removed all the other functions to test.
manager.on('end', function () {
// Reset:
var x_field_incrementor = 0;
var y_advancer_incrementor = 0;
console.log("end");
});
I'm still wondering if there is something limiting the addEventListener(). I'm pretty sure that this operation is faster than the handling if a task is for example taking longer than 50 ms. How long would event start queuing up in this case?
I've experienced something similar where the joystick freezes, and I don't think it was my event handler taking too long - it occurred when my game was running at very low fps
Nipplejs is very good in terms of feature-set but upon profiling it seems there are other performance issues - e.g. taking 2-3ms because of what seems like reading a dom style after writing to the dom (forcing the browser to re-render)
this happens on 0.9.1: see the long handler (as well as the style recalculation/layout I have highlighted which costs another 2ms later on when the browser does it) I think the style recalculation/layout can be avoided using transform: translate instead of modifying top/etc

I think the style recalculation/layout can be avoided using transform: translate instead of modifying top/etc
Super good suggestion.
Back in the days I wanted to have full browser support and it was easier this way.
But I guess now, translate are way more supported than before.
If you feel up to the task @MCArth you can submit a PR for it. Otherwise I'll do it once I have some time.