For server-side stuff you have a couple of options. The first is to entirely extrapolate all your collisions working off of the assumption that you will have frequent-enough messages from clients, communicating all meaningful state change through the server, which then will run validation on game events only as it receives IO callbacks from the client connections.
The second way, which you seem to prefer, is to run your own loop while whilst you process IO callbacks. Although setInterval and setTimeout will accomplish this, you have a much more fine-grained set of tools to control this: setImmediate(callbacks, [[arg], ...])
and process.nextTick(callback)
.
Process.nextTick will run your callback before other IO events, so long as you haven't stacked up a recursively infinite stack of callbacks (if it exceeds a certain number, process.maxTickDepth, then it will yield to the IO callbacks).
SetImmediateCallback is similar to process.nextTick in that it acts every tick, but only one of the queued callbacks gets executed on every tick, rather than all queued callbacks.
Using these will look similar to setTimeout or requestAnimationFrame.
function gameLoop() {
updateCollisions();
process.nextTick(gameLoop);
}
process.nextTick(gameLoop);
The advantage of these is that you're not dependent on V8's implementation of setTimeout and setInterval. These are more of a direct line to Node's event loop. Just be sure you don't starve the IO if you are using process.nextTick. updateCollisions should be guaranteed to not take that long at all.