zthreader
Version:
JavaScript library that provides pseudo-threading for leveraging resources during long, CPU intensive operations
169 lines (140 loc) • 6.72 kB
HTML
<html>
<head>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable = no" name="viewport">
<meta charset="utf-8" />
<title>ZThreader example</title>
<script src="../dist/zthreader.min.js" type="text/javascript"></script>
</head>
<body>
<div id="container">
<h1>Example JavaScript "threading" application #2</h1>
<p>
Below two buttons to execute a heavy operation.
</p>
<p>
The <strong>normal</strong> one will complete
faster, but will leave the application unresponsive (there <i>should</i> be a GIF image
showing a spinning animation during the operation but it is likely to be frozen (if it
appears at all!), and on some browsers you'd even be unable to switch to different tabs!).
As a matter of fact, if you're unlucky the browser/tab might even crash as the script execution
takes longer than the browser deems feasible!! Just to be sure, open this page in a new window and
test the "normal" button there in case the thing decides to crash!!
</p>
<p>
The <strong>threaded</strong> one will take slightly longer to complete, but will leave plenty of
CPU cycles to render the application interface, keeping it responsive (i.e. GIF animation
should run smoothly, switching to other tabs should be possible (will postpone script execution
until return though!). As a matter of fact, if you're feeling adventurous, you can click this
button multiple times to run several threads at the same time (they will each take longer to
complete, but with the benefit that the UI still remains responsive! also note that upon each
individual threads completion, the remainder will complete faster as more resources become available).
</p>
<p>
Upon completion of each individual execution, an alert box should popup to show the results (elapsed time).
</p>
<button id="normal" onclick="normal();">normal execution</button>
<button id="threaded" onclick="threaded();">threaded execution</button>
<div id="state"></div>
<img id="loader" src="assets/loader.gif" style="display:none;" />
</div>
<script type="text/javascript">
// initialize ZThreader to ensure 60 fps animation at 40% CPU load
zThreader.init( 0.4, 60 );
var MAX_ITERATIONS = 150000000; // a ridiculous amount to overload the CPU
var startTime, elapsedTime;
var isRunning = false;
var isRunningNormal = false;
var stats = { "normal" : 0, "concurrent" : 0 };
// invoked when starting the execution
function handleStart()
{
isRunning = true;
document.getElementById( "loader" ).style.display = "block";
startTime = +new Date();
}
// invoked when completing a full execution
function handleComplete()
{
elapsedTime = +new Date() - startTime;
if ( isRunningNormal )
stats.normal = elapsedTime;
if ( zThreader.getAmountOfThreads() === 0 )
{
isRunning = false;
document.getElementById( "loader" ).style.display = "none";
showState( "currently running 0 operations" );
var msg;
if ( isRunningNormal )
{
msg = "total operation(s) took: " + elapsedTime + " milliseconds to complete.";
}
else
{
// calculate some statistics
msg = ( "total " + stats.concurrent + " operation(s) took: " + elapsedTime + " milliseconds to complete" );
if ( stats.concurrent > 1 ) {
msg += " ( " + ( elapsedTime / stats.concurrent ).toFixed( 0 ) + " milliseconds per operation ) ";
}
if ( stats.normal != 0 ) {
msg += " ran at " + (( stats.normal / ( elapsedTime / stats.concurrent )) * 100 ).toFixed( 2 ) + " % of un-threaded speed";
}
stats.concurrent = 0; // reset
}
alert( msg );
}
else {
showState( "currently running " + zThreader.getAmountOfThreads() + " concurrent threads" );
}
}
// convenience method to display a message in the DOM
function showState( msg ) {
document.getElementById( "state").innerHTML = msg;
}
// the fiendishly heavy function we'd like to execute
function heavyOperation( number ) {
Math.sin( Math.pow( Math.random() * MAX_ITERATIONS, number ));
}
// the normal, non-threaded execution of the heavy function
function normal() {
if ( isRunning ) {
return;
}
isRunningNormal = true;
handleStart();
for ( var i = 0; i < MAX_ITERATIONS; ++i ) {
heavyOperation( i );
}
handleComplete();
isRunningNormal = false;
}
// the threaded version of running the fiendishly heavy function
function threaded()
{
var thread = new zThread({
completeFn: handleComplete,
// here we define our own custom override of
// the ZThread internal execution handler to
// run the heavy operation
executionFn: function() {
// the amount of times we call the "heavyOperation"-function
// per iteration of the internal execution method
var stepsPerIteration = 2500;
for ( var i = 0; i < stepsPerIteration; ++i ) {
if ( this._iterations >= MAX_ITERATIONS ) {
return true;
} else {
// execute operation (and increment iteration)
heavyOperation( ++this._iterations );
}
}
return false;
}
});
handleStart();
thread.run();
stats.concurrent = Math.max( stats.concurrent, zThreader.getAmountOfThreads() );
showState( "currently running " + zThreader.getAmountOfThreads() + " concurrent threads" );
}
</script>
</body>