I've found that a steady method for timing is by calculating the number of samples to render per "tick" and decrement the counter after each completed sample when rendering audio to the buffer in JavaScriptNode/ScriptProcessor. Eg.
Upon the counter reaching zero, the render loop actually jumps to do sequencing and effects/modulation and then resets to counter.
In my case, the tick occurs at 50Hz because that's the PAL frame clock used in Amiga and MS-DOS module trackers like Scream Tracker and FastTracker 2. Typically trackers use a "speed" setting to additionally specify the number of ticks per pattern step - usually 6.
Although you do get sample-accurate timing, you also get latency up to the size of a single audio buffer (I use 4096 samples). While this isn't really an issue when doing purely playback, it obviously is when the audio is controlled real-time (eg. MIDI).