I have a loop that needs to be run 200 million times in the browser. This is a simulator that several people should use regularly. It takes about 15 minutes to start, but during this time, browsers often come out with a warning that βthis script takes too longβ, etc., and it completely freezes Firefox during the function. It also means that the page is not updating my status indicator (this is just a number).
I have a google exit for javascript and read the first 4 pages of hits. Some discuss the new keyword "yield", but there is only one description and an example that I find obscure, for example. "The function containing the yield keyword is a generator. When you call it, the formal parameters are bound to the actual arguments, but its body is not actually evaluated." Is yield suitable for the user interface?
One of the few solutions I found is an old post that uses an outdated caller argument and a timer to call itself: http://www.julienlecomte.net/blog/2007/10/28/
However, the above example does not contain any loop or state variables, and when I add them, it falls apart and my net result is always zero.
It also does not perform chunking, but I found several other examples that use "index% 100 == 0" at each iteration. However, this seems to be a slow way to do this. For example. this is:
How to stop javascript intensive loop from freezing browser
But it has no way to update progress and is not inferior to the user interface (so the browser still hangs). Here is a test version that freezes the browser at runtime:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script> var spins = 1000000 var chunkSize = 1000; var chunk; function Stats() {this.a=0}; var stats = new Stats(); var big; var index = 0; var process = function() { for (; index < spins; index++) { stats.a++; big = (big/3.6)+ big * 1.3 * big / 2.1; console.write(big); </script> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Untitled Document</title> </head> <body onload="process()"> <div id=result>result goes here.</div> </body> </html>
and here is another try, which stats.a always zero (so I assume there are some problems with defining the scope):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script> var spins = 1000000 var chunkSize = 1000; var chunk; function Stats() {this.a=0}; var stats = new Stats(); function doIt() { function spin() { for (spinIx=0; (spinIx<chunkSize) && (spinIx+chunk < spins); spinIx++) { stats.a++; } } for (chunk =0; chunk < spins; chunk+=chunkSize){ setTimeout(spin, 5); document.getElementById("result").innerHTML = stats.a; } document.getElementById("result").innerHTML = stats.a; } </script> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Untitled Document</title> </head> <body onload="doIt()"> <div id=result>result goes here.</div> </body> </html>
I spent 48 hours trying to get this to work - either I'm very dumb or it's very complicated. Any ideas?
Several people have suggested web workers. I tried a few days to get it working, but I could not find a similar example that passes a number, etc. Below is my last attempt to get it to work, but the result is always 0 when it should be 100000. Ie it fails just like my second example above.
spinMaster.html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> </head> <body> <script> if(typeof(Worker)==="undefined") { document.write("<h1>sorry, your browser doesnt support web workers, please use firefox, opera, chorme or safari</h1>"); } var worker =new Worker("spinWorker.js"); worker.postMessage({times:1000000}); worker.onmessage=function(event){ document.getElementById("result").innerHTML=event.data; }; </script> <div id="result">result goes here</div> </body> </html>
spinWorker.js
function State() { this.a=0; } var state = new State(); self.addEventListener('message', spin, false); function spin(e) { var times, i; times = e.data.times;
total result: 0