Jul 02 2009

Javascript Time Slice Proc

Published by

Hi. If you’re coming here looking for my Javascript Timeslice class, I’m having trouble getting it posted. It seems that getting code to format propertly in WordPress is like, well, getting code to format properly in WordPress.

The problem that this class addresses is when a lengthy background operation must take place from a webpage. Since javascript has the thread, the browser cannot refresh. So this class allows the background process to broken up into atomic pieces, and each one is called in turn, using a timer() to evoke the next ‘slice.’ In this way a little bit of work is performed in the background that also modified the DOM such that when control is returned to the browser that the webpage changes (via a progress bar or similar) to tell the user that work is progressing.

This may be moot now that javascript worker threads are a reality, but here it is anyhow. I’ll post usage information at some later time unless someone wants to ping me for it.

/////////////////////////////////////////////////////////////////////////////////////////
//
//  clsTimeSlice
//
//  The atomic time slice object. Represents either a function call or a method call
//  to an object. The evoked function/method must answer false to continue processing, or
//  true to terminate it.
//
function clsTimeSlice( fnSlice, objObj, name, latency )
{
 this.fnSlice = fnSlice;
 this.obj     = objObj;
 this.name    = name;
 this.latency = ( null == latency || latency < 1 )
? clsTimeSlicedProc.SLICE_LATENCY
: latency;
}

clsTimeSlice.prototype.exec = function()
{
var bRet;
if( null != this.obj )
bRet = this.fnSlice.call( this.obj );
else
bRet = this.fnSlice();
return bRet;
}

/////////////////////////////////////////////////////////////////////////////////////////
//
//  clsTimeSlicedProc
//
//  Container for a time-sliced procedure.
//
function clsTimeSlicedProc( sObjectName )
{
this.init( sObjectName );
}
clsTimeSlicedProc.CHAIN_INDEX   = -1;
clsTimeSlicedProc.SLICE_LATENCY = 2;   // #ms between slices

clsTimeSlicedProc.prototype.init = function( sObjectName )
{
 this.name       = sObjectName;
 this.slices     = new Array();
 this.sliceChain = null;
 this.latch      = false;
 this.next       = 0;
 this.error      = 0;
 this.run        = false;
}

clsTimeSlicedProc.prototype.reset    = function() { this.init( this.name ); }
clsTimeSlicedProc.prototype.sliceCnt = function() { return this.slices.length; }
clsTimeSlicedProc.prototype.slice    = function( idx )
{
if( idx < this.sliceCnt() )
return this.slices[ idx ];
return null;
}

clsTimeSlicedProc.prototype.latched      = function()             { return this.latch; };
clsTimeSlicedProc.prototype.addSlice     = function( s )          { this.slices[ this.slices.length ] = s; return s; }
clsTimeSlicedProc.prototype.createSlice  = function( f, o, n, l ) { this.addSlice( new clsTimeSlice( f, o, n, l )  ); return this; }
clsTimeSlicedProc.prototype.addFunction  = function( f, n, l )    { this.addSlice( new clsTimeSlice( f, null, n, l )  )._f = true; return this; }
clsTimeSlicedProc.prototype.chain        = function( f, o, n, l ) { this.sliceChain = new clsTimeSlice( f, o, n,  l ); return this; }
clsTimeSlicedProc.prototype.setErrorCode = function( c )          { this.error = c; }
clsTimeSlicedProc.prototype.hasError     = function()             { return !!( this.error != 0 ); }
clsTimeSlicedProc.prototype.finish       = function()             { this.next = clsTimeSlicedProc.CHAIN_INDEX; }

clsTimeSlicedProc.prototype.begin        =
 function()
 {
 if( this.latch )
 return false;

 this.latch = true;
 this._doSlice( this.next );
 return true;
 }

clsTimeSlicedProc.prototype.setNextSlice =
 function( indexOrName )
 {
 if( typeof indexOrName == "string" )
 {
 // search for a slice by name
 for( var idx = 0; idx < this.slices.length; idx++ )
 {
 if( this.slice( idx ).name == indexOrName )
 {
 this.next = idx;
 break;
 }
 }
 if( idx >= this.slices.length )
 alert( this.name + ": Not able to find slice with tag '" + indexOrName + "'" );
 }
 // must allow index to exceed slice count in order for loop to ever terminate!
 else if( indexOrName <= this.sliceCnt() )
 this.next = indexOrName;
 }

clsTimeSlicedProc.prototype._doSlice =
 function( iIndex )
 {
 var l = ( iIndex in this.slices ) ? this.slices[ iIndex ].latency : clsTimeSlicedProc.SLICE_LATENCY;
 setTimeout( this.name + ".exec( " + iIndex + ")", l );
 }

clsTimeSlicedProc.prototype.exec =
 function( iIndex )
 {
 if( clsTimeSlicedProc.CHAIN_INDEX == iIndex )
 {
 if( null != this.sliceChain )
 this.sliceChain.exec();
 this.sliceChain = null;            // chain is a one-shot deal
 this.latch = false;
 }
 else
 {
 if( !this.hasError() && iIndex < this.sliceCnt() )
 {
 this.setNextSlice( iIndex + 1 );
 if( this.slices[ iIndex ].exec() || this.slices[ iIndex ]._f )
 iIndex = this.next;
 this._doSlice( iIndex );
 }
 else
 {
 this._doSlice( clsTimeSlicedProc.CHAIN_INDEX );
 }
 }
 }

No responses yet

Trackback URI | Comments RSS

Leave a Reply