WaBis

walter.bislins.ch

Datei: JSG3D: async.js

Inhalt der Datei: ./javascript/jsg3d/src/async.js
// async.js (C) Walter Bislin
// url: http://walter.bislins.ch/doku/async
//
// Usage:
//
// MyClass.prototype.myLoopFunction = function( aParam ) {
//   do one loop step ...
//   aParam.Ix++;
//   return aParam.Ix < last;
// }
//
// MyClass.prototype.myLastFunction = function( ) {
//   do last thing...
// }
//
// MyClass.prototype.myAsyncFunctions = function( ) {
//   Async.Call( this, this.myLoopFunction, { Ix: 0 } );
//   Async.Call( this, this.myLastFunction );
// }
//
// var myObj = new MyClass();
// myObj.myAsyncFunctions();

function CAsync() {
  this.RunTime = 12;
  this.WaitTime = 0;
  this.TimerStartTime = 0;
  this.SyncMode = false;
  this.Debug = false; // true -> GetElapsedTime returns always 0
  this.OnException = function(err,caller) { alert(err); return true; };
  this.WaitingQueue = { Head: null, Tail: null };
  this.RunningQueue = { Head: null, Tail: null };
  this.Timer = null;
}

// Private Functions

CAsync.prototype.ClearQueue = function ( aQueue ) {
  aQueue.Tail = null;
  if (!aQueue.Head) return;
  while (aQueue.Head) {
    var qe = aQueue.Head;
    aQueue.Head = qe.Next;
    qe.Next = null;
  }
}

CAsync.prototype.AppendQueueElement = function ( aQueue, aQueueElement ) {
  if (aQueue.Tail) aQueue.Tail.Next = aQueueElement;
  aQueue.Tail = aQueueElement;
  if (!aQueue.Head) aQueue.Head = aQueueElement;
}

CAsync.prototype.AppendQueue = function ( aQueue1, aQueue2 ) {
  if (!aQueue2.Head) return;
  if (aQueue1.Tail) aQueue1.Tail.Next = aQueue2.Head;
  aQueue1.Tail = aQueue2.Tail;
  if (!aQueue1.Head) aQueue1.Head = aQueue2.Head;
  aQueue2.Head = null;
  aQueue2.Tail = null;
}

CAsync.prototype.RemoveFirstQueueElement = function ( aQueue ) {
  if (!aQueue.Head) return null;
  var qe = aQueue.Head;
  aQueue.Head = qe.Next;
  qe.Next = null;
  if (!aQueue.Head) aQueue.Tail = null;
  return qe;
}

CAsync.prototype.NewQueueElement = function ( aObj, aFn, aParam, aDelay, aBeforeCallCB, aAfterCallCB ) {
  return {
    Next: null,
    Obj: aObj,
    Fn: aFn,
    Param: aParam,
    Delay: aDelay,
    BeforeCallCB: aBeforeCallCB,
    AfterCallCB: aAfterCallCB
  };
}

CAsync.prototype.BeginQueue = function () {
  this.RunningQueue.Head = this.WaitingQueue.Head;
  this.RunningQueue.Tail = this.WaitingQueue.Tail;
  this.WaitingQueue.Head = null;
  this.WaitingQueue.Tail = null;
}

CAsync.prototype.EndQueue = function ( bKeepCurrentElement ) {
  if (!bKeepCurrentElement) {
    this.RemoveFirstQueueElement( this.RunningQueue );
  }
  this.AppendQueue( this.WaitingQueue, this.RunningQueue );
}

CAsync.prototype.StartAsyncCalls = function () {
  var again = true;
  while (again) {
    if (this.RunningQueue.Head) return;
    if (!this.SyncMode && this.Timer) return;
    var qe = this.WaitingQueue.Head;
    if (!qe) return;
    var me = this;
    if (qe.BeforeCallCB) {
      try {
        this.CallFn( qe.BeforeCallCB, qe );
      } catch(err) { }
    }
    if (this.SyncMode) {
      again = this.OnTimer();
    } else {
      var time = this.WaitTime;
      if (qe.Delay > 0) time = qe.Delay;
      this.Timer = setTimeout( function(){ me.OnTimer(); }, time );
      return;
    }
  }
}

CAsync.prototype.CallFn = function ( aFn, aQueueElement ) {
  if (aQueueElement.Obj) {
    return aFn.call( aQueueElement.Obj, aQueueElement.Param );
  } else {
    return aFn( aQueueElement.Param );
  }
}

CAsync.prototype.OnTimer = function () {
  //console.log( 'CAsync.OnTimer' );
  if (this.Timer) clearTimeout( this.Timer );
  this.Timer = null;
  this.BeginQueue();
  var qe = this.RunningQueue.Head;
  if (!qe) return false;
  try {
    var doRepeat = false;
    doRepeat = this.CallFn( qe.Fn, qe );
    doRepeat = doRepeat || false;
    if (qe.AfterCallCB && !doRepeat) {
      try {
        this.CallFn( qe.AfterCallCB, qe );
      } catch(err) { }
    }
    this.EndQueue( doRepeat );
    if (this.Timer) clearTimeout( this.Timer );
    this.Timer = null;
    if (this.SyncMode) {
      return true;
    } else {
      this.StartAsyncCalls();
    }
  }
  catch(err) {
    if (qe.AfterCallCB) {
      try {
        this.CallFn( qe.AfterCallCB, qe );
      } catch(err) { }
    }
    var me = this;
    if (!this.OnException || (this.OnException && this.OnException(err,me))) {
      this.Stop();
      throw err;
    }
  }
  return false;
}

// Public Functions

CAsync.prototype.CallObj = function( aObj, aFn, aParam, aBeforeCallCB, aAfterCallCB ) {
  // aFn, aBeforeCallCB, aAfterCallCB =
  //   doRepeat = aObj.function( aParam ) or
  var qe = this.NewQueueElement( aObj, aFn, aParam, 0, aBeforeCallCB, aAfterCallCB );
  this.AppendQueueElement( this.WaitingQueue, qe );
  this.StartAsyncCalls();
}

CAsync.prototype.Call = function( aFn, aParam, aBeforeCallCB, aAfterCallCB ) {
  // aFn, aBeforeCallCB, aAfterCallCB =
  //   doRepeat = function( aParam )
  this.CallObj( null, aFn, aParam, aBeforeCallCB, aAfterCallCB );
}

CAsync.prototype.CallObjDefered = function( aDelay, aObj, aFn, aParam, aBeforeCallCB, aAfterCallCB ) {
  // aFn, aBeforeCallCB, aAfterCallCB =
  //   doRepeat = aObj.function( aParam ) or
  var qe = this.NewQueueElement( aObj, aFn, aParam, aDelay, aBeforeCallCB, aAfterCallCB );
  this.AppendQueueElement( this.WaitingQueue, qe );
  this.StartAsyncCalls();
}

CAsync.prototype.CallDefered = function( aDelay, aFn, aParam, aBeforeCallCB, aAfterCallCB ) {
  // aFn, aBeforeCallCB, aAfterCallCB =
  //   doRepeat = function( aParam )
  this.CallObjDefered( null, aFn, aParam, aDelay, aBeforeCallCB, aAfterCallCB );
}

CAsync.prototype.Stop = function( ) {
  if (this.Timer) clearTimeout( this.Timer );
  this.Timer = null;
  this.ClearQueue( this.WaitingQueue );
  this.ClearQueue( this.RunningQueue );
}

CAsync.prototype.StartTimer = function( ) {
  this.TimerStartTime = new Date().getTime();
}

CAsync.prototype.IsTimerExpired = function( aTimeMS ) {
  if (this.SyncMode || this.Debug) {
    return false;
  }
  aTimeMS = aTimeMS || this.RunTime;
  var timeNow = new Date().getTime();
  return ((timeNow - this.TimerStartTime) > aTimeMS);
}

CAsync.prototype.GetElapsedTime = function( ) {
  if (this.SyncMode || this.Debug) { return 0; }
  var timeNow = new Date().getTime();
  return timeNow - this.TimerStartTime;
}

// Public Object

var Async = new CAsync();

Weitere Infos zur Seite
Erzeugt Montag, 1. August 2016
von wabis
Zum Seitenanfang
Geändert Montag, 1. August 2016
von wabis