I had a look into the Blink codebase to answer this question about the maximum possible number of timers in JavaScript.
New timers are created by DOMTimerCoordinator::InstallNewTimeout(). It calls NextID() to retrieve an available integer key. Then, it inserts the new timer and the corresponding key into timers_.
int timeout_id = NextID();
timers_.insert(timeout_id, DOMTimer::Create(context, action, timeout,
                                            single_shot, timeout_id));
NextID() gets the next id in a circular sequence from 1 to 231-1:
int DOMTimerCoordinator::NextID() {
  while (true) {
    ++circular_sequential_id_;
    if (circular_sequential_id_ <= 0)
      circular_sequential_id_ = 1;
    if (!timers_.Contains(circular_sequential_id_))
      return circular_sequential_id_;
  }
}
What happen if all the IDs are in use?
What does prevent NextID() from entering in a endless loop?
The whole process is explained with more detail in my answer to that question.
 
    