I’m working on a web app that displays (and highlights) music notation as a song plays. Unfortunately, setInterval falls short of expectations as it’s highly unreliable and skippy, even on relatively low redraw resolutions.
See this demo – all I’m doing is ‘activating’ a bar every x msec, and some of the blocks skip. It might not be bad on fast PCs, but once actual work is done in the loop, it will definitely fall apart.
I’m looking for a solution that will let me run a ui redraw reliably and quickly, without the unacceptable delays. If it helps, the HTML5 audio element is the master node, and all the data will be pulled from it during playback (i.e. audio.currentTime).
Any suggestions are appreciated – perhaps I’m looking for some sort of javascript threading (that doesn’t seem to exist). No matter if it’s not widely supported, I’m just looking to get the job done on a proof of concept here.
Your be_busy function doesn’t actually ever enter the while loop to be busy for 100 ms. You need to flip the
<to a>or>=. So those skips are just from delays in your browser getting a bit behind on the timing. But in reality those delays are insignificant if you have a proper busy function. If you flip the sign you’ll get this: http://jsfiddle.net/Paulpro/PvQFh/40/embedded/result/It is expected that it will skip over blocks like that because Javascript is single threaded. So your first call to refresh_ui will occur after 50 ms. Your next after 100 ms. And you should see the first two blocks set active.
Then at 120 ms, be_busy is called and it holds the thread for 100ms. so refresh_ui cannot be called (whether you use setTimeout or setInterval doesn’t change this fact) until 220ms. refresh_ui will be called at 220 and you’ll see the third block set active. Then at 240 ms be_busy will be called again. So the next refresh_ui cannot occur until 340 ms. When it does occur the 5th block will be set to active in (340/80 = 4.x).
The fourth block being skipped is expected behaviour in the best browsers. A browser which doesn’t skip that block is probably lagging behind even more.
So you should have the first three blocks coloured then a a white box then 2 red ones then a white etc. and every 10 groups of two red blocks there will be a single white block.
The only real way around this is to split be_busy up into a bunch of smaller functions that split the job into pieces, or use Web Workers to do your background (busy) processing, but Web Workers will only work in very recent browsers.