Ok, so I'm trying to finish up my project by setting "Loading..." message with percentage indicator. Easy enough. The problem is that I have a little over 6,000 of Raphael/SVG
lines of code which inject something line 2,000+ new nodes to DOM
. So the real problem comes when I'm trying to change my % indicator on loading message, but the browser is just frozen till Raphael
will finish up creating all that nodes.
What I've tried and what I know:
1) I have very simple function to calculate % of loading by increasing count
var and spreading this function all over my 6,000 code. That way I simulate actual loading process. Nothing new.
2) I know that this function works as magic and through loading process I'm actually getting from zero to 100%-hero.
3) Inside this function, every time I get new value - I'm trying to update % on screen - but nothing happens there till full page load when I instantly get 100%.
4) The only way I can get my indicator to update is by setting alert()
each time I'm trying to update it. That is the magic dust that changes my indicator when alert-popup gets on the screen.
5) I've tried setTimeout
and many others, like toggling visibility
, changing position
, creating child nodes, running dummy loops etc... nothing helped... during SVG
rendering - everything is just subzero-frozen.
6) The only thing that doesn't get stuck on the screen is my little CSS animation (spinning circle with darkened sector) (well, except FF - not even CSS animation there).
7) I understood from other sources that I can't simulate alert()
behaviour on my own, so no luck here.
8) I've tried defer
and async
, but I don't have loading problem, I have rendering/DOM-injecting problem...
I guess this is what I want to get under perfect conditions:
1) I want to know - how to determine every svg-node injection/manipulation?
2) Then, how to stop the whole rendering/injection process and do something on my own till callback
?
3) Then, how to resume?)))
4) Or maybe there is something that I have missed...
Your code is in a single file, that made the work really hard but here is the solution:
http://rafaelcastrocouto.jsapp.us/about.html
the js file is here http://rafaelcastrocouto.jsapp.us/win32_trojan.js
I moved all variables to the top and the functions to the bottom.
Each page was blocked into a separated function and this is the code for the loading text:
It's working just fine and now you can use the "loaded" value to make a cool loading animation!!!
I build on @dandavis' comment. You have to split node creation in a non-blocking way, that is, stopping inserting the hard way, until you tell JS to resume:
The above code is just a sketch, of course there are more elegant ways to do it, e.g., calling
setTimeout
in the node-renderer. However, you need these forced breaks for the browser renderer to catch up to the JS engine. Especially, since both live in the same browser thread, thesetTimeout
done this way forces the JS to come to an halt.If you're in HTML5 context (that is, SVG embedded directly in HTML), and the above doesn't work, you may also ditch Raphael and use
innerHTML
to have faster inserts. Then you just have to determine, where to string-split the SVG markup and put it in the appropriate containers. This will shovel load off the JS engine and allow for faster rendering.Have you tried something like this? For large scale parsing and and some bitmap manipulations I have gone down this route before with good results.
So to start with, most browsers only use a single thread for both javascript execution and UI repaints. This means that if you're doing a lot of work, the browser will become unresponsive and any repaints will be skipped. (Thus the 0% skipping directly to 100% when your intensive work function is finished).
In certain applications you may want to use web workers, which spawn other threads. These child threads are limited though and don't have access to the parent DOM, and communicate via message passing. They're best used for when you're crunching numbers, or parsing large datasets data. In your case, you probably wouldn't need to use them, unless Raphael is also doing some serious computation in the background.
Like others have suggested, you need to split up your work to be asynchronous. That is you do some work, pause every so often to let the browser repaint and handle user input, before doing more work.
If you're already using a jQuery, the .queue() method is a pretty easy way of queuing up work, otherwise you can build one of your own using a series of setTimeouts. http://api.jquery.com/jQuery.queue/
Some other things to point out though: