Figured out an annoying bug with component removal

I just thought I would share my longstanding bug that I’ve finally figured out, in case anyone else is baffled by this behaviour. The issue I was having is that somehow I was trying to remove the same component multiple times and that causes errors (cannot read property 'dispose' of undefined). So, I figured I can just use a hasComponent check, right?

But the bug was still happening sometimes! The main way to reproduce it was playing my game multiplayer in 2 tabs, and the unfocussed tab would error when tabbing back in. I put this down to maybe doing stuff in async functions rather than in the main frame loop, and I figured after reworking my networking to do all the adding and removing during the execute function it would work.


So, I eventually had to deep dive into the debugger to see what gives, and I finally figured it out. If you add and remove the same component multiple times during the same frame, it stacks up multiple removed component types on the entity, which in turn calls the component removal code multiple times in the deferred removal phase. The reason it was being called multiple times is because requestAnimationFrame slows down a great deal in background tabs, thus causing the WebSocket messages to pile up, so sometimes multiple sequences of adding and removing a component were happening in the same execute cycle.

The simplest solution I’ve found has been to use the immediate mode in the removeComponent call. I guess I’m losing some functionality doing this, but it’s fixed everything for me. Not sure if this should be considered an ecsy bug or not, but it’s certainly something to be aware of. If people think this isn’t the expected behaviour, I might consider trying to make a PR that fixes it.