Javascript Daemons Management

  • Revision slug: Web/JavaScript/Timers/Daemons
  • Revision title: Javascript Daemons Management
  • Revision id: 418963
  • Created:
  • Creator: Sheppy
  • Is current revision? No
  • Comment Moved From JavaScript/Timers/Daemons to Web/JavaScript/Timers/Daemons

Revision Content

In Computer science a daemon is a task that runs as a background process, rather than being under the direct control of an interactive user. In JavaScript programming language, are called daemons all processes created by JavaScript timers or by a Worker instantiation. Here are some code snippets which simplify and abstract the management of daemons.

The following daemons management framework is the major version of setInterval – A little framework.

Introduction

Sometimes a page uses dozens and dozens of animations. In such a condition is difficult and unnatural to keep track of all events started and then to stop them when appropriate through the clearTimeout() function. A possible approach to solve this problem is to nest all the informations needed by each animation to start, stop, etc. etc. in different objects (daemons) and then to create a constructor for such class of objects (Daemon) in order to standardize and simplify the instantiation of them.

Note: A minimalistic version of it (MiniDaemon) is published here. This more complex version of it is nothing but a big and scalable collection of methods for the Daemon constructor. But the Daemon constructor itself is nothing but a clone of MiniDaemon with an added support for init and onstart functions declarable during the instantiation of the daemon. So the MiniDaemon framework will remain the recommended way for simple animations, because Daemon without its collection of methods is essentially a clone of it.

The architecture of the Daemon constructor explicitly avoids the use of closures. It also offers an alternative way to pass the this object to the callback functions (see The "this" problem for details).

Advantages of this approch:

The code

The code of this framework is splitted into three files:

  • fork.js (the core),
  • daemon-safe.js (an extension of the core which adds a replacement of setInterval with a recursive invocation of setTimeout),
  • daemons-methods.js (a wide and highly scalable collection of methods).

The only indipendent module is fork.js: both daemon-safe.js module and daemons-methods.js module require fork.js to work.

About the “callback arguments” polyfill

In order to make this framework compatible with Internet Explorer (which doesn't support sending additional parameters to timers' callback function, neither with setTimeout() or setInterval()) we included the IE-specific compatibility code (commented code), which enables the HTML5 standard parameters passage functionality in that browser for both timers (polyfill), at the end of the fork.js module.

fork.js

What follows is the module which declare the Daemon constructor (the core of this framework). The Daemon constructor itself is nothing but a clone of the little framework MiniDaemon with an added support for init and onstart functions (declarable during the instantiation of the daemon). So the MiniDaemon framework will remain the recommended way for simple animations, because Daemon without its collection of methods is essentially a clone of it.

 /*\
 |*|
 |*|                     *******************************
 |*|                     *           fork.js           *
 |*|                     *******************************
 |*|
 |*|  ver. 1.0 rev. 1
 |*|
 |*|  fork.js - A JAVASCRIPT HIGLY SCALABLE DAEMONS MANAGER.
 |*|
 |*|  https://developer.mozilla.org/en-US/docs/JavaScript/Timers/Daemons
 |*|  https://developer.mozilla.org/User:fusionchess
 |*|
 |*|  This framework is released under the GNU Public License, version 3 or later.
 |*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
 |*|
 \*/
 
"use strict";
 
 
      /****************************
      *     THE DAEMON SYSTEM     *
      ****************************/
 
 
 
/* The global "Daemon" constructor */
 
  function Daemon (oOwner, fTask, nRate, nLen, fInit, fOnstart) {
    if (!(this && this instanceof Daemon)) { return; }
    if (arguments.length < 2) { throw new TypeError("Daemon - not enough arguments"); }
    if (oOwner) { this.owner = oOwner };
    this.task = fTask;
    if (isFinite(nRate) && nRate > 0) { this.rate = Math.floor(nRate); }
    if (nLen > 0) { this.length = Math.floor(nLen); }
    if (fOnstart) { this.onstart = fOnstart; }
    if (fInit) {
      this.onstop = fInit;
      fInit.call(oOwner, this.INDEX, this.length, this.BACKW);
    }
  }
 
    /* Create the Daemon.blank() constructor and the global Daemon.context object */
 
  Daemon.blank = function () {};
  Daemon.context = Daemon.blank.prototype; /* Make love with the GC :-) */
  Daemon.blank.prototype = /* Important! */ Daemon.prototype;
  Daemon.context.constructor = Object;
 
    /* These properties can be manually reconfigured after the creation of the daemon */
 
  Daemon.prototype.owner = Daemon.context;
  Daemon.prototype.task = null;
  Daemon.prototype.rate = 100;
  Daemon.prototype.length = Infinity;
  Daemon.prototype.reversals = 0;
  Daemon.prototype.onstart = null;
  Daemon.prototype.onstop = null;
 
    /* These properties should be read-only after the creation of the daemon */
 
  Daemon.prototype.SESSION = -1;
  Daemon.prototype.INDEX = 0;
  Daemon.prototype.PAUSED = true;
  Daemon.prototype.BACKW = true;
 
 
/* SYSTEM REQUIRED Daemon global object methods */
 
  Daemon.forceCall = function (oDmn) {
 
    oDmn.INDEX += oDmn.BACKW ? -1 : 1;
 
    var
      bBreak = oDmn.task.call(oDmn.owner, oDmn.INDEX, oDmn.length, oDmn.BACKW) === false,
      bEnd = oDmn.isAtEnd(), bInvert = oDmn.reversals > 0;
 
    if (bEnd && !bInvert || bBreak) {
      oDmn.pause();
      return false;
    }
 
    if (bEnd && bInvert) {
      oDmn.BACKW = !oDmn.BACKW;
      oDmn.reversals--;
    }
 
    return true;
 
  };
 
 
/* SYSTEM NOT REQUIRED Daemon global object methods */
 
  /**
  * Daemon global object optional methods (shortcurts). You could safely remove all or some of them,
  * depending on your needs. If you want to remove them and are using the Daemon.safe subsystem you
  * should remove also the Daemon.safe global object methods which require them.
  **/
 
  Daemon.construct = function (aArgs) {
    var oDmn = new this.blank();
    this.apply(oDmn, aArgs);
    return oDmn;
  };
 
  Daemon.buildAround = function (oCtx, nRate, nLen) {
    if (!oCtx.perform) { throw new TypeError("You can not create a daemon around an object devoid of a \"perform\" function"); }
    return new this(oCtx, oCtx.perform, nRate || null, nLen || null, oCtx.create || null, oCtx.prepare || null);
  };
 
    /* Warning! Calling Daemon.incorporate(@func) will modify the @func.prototype property! */
 
  Daemon.incorporate = function (fConstr) {
    var oLegacy = fConstr.prototype;
    fConstr.prototype = new Daemon.blank();
    fConstr.prototype.legacy = oLegacy;
    return fConstr;
  };
 
 
/* SYSTEM REQUIRED Daemon instances methods */
 
  Daemon.prototype.isAtEnd = function () {
    return this.BACKW ? isFinite(this.length) && this.INDEX < 1 : this.INDEX + 1 > this.length;
  };
 
  Daemon.prototype.synchronize = function () {
    if (this.PAUSED) { return; }
    clearInterval(this.SESSION);
    this.SESSION = setInterval(Daemon.forceCall, this.rate, this);
  };
 
  Daemon.prototype.pause = function () {
    clearInterval(this.SESSION);
    this.PAUSED = true;
  };
 
 
/* SYSTEM NOT REQUIRED Daemon instances methods */
 
  /**
  * Basical user interface. You could remove this method, but your daemon will be virtually unusable.
  * All other optional instances methods depend on this one or on the previous ones.
  **/
 
  Daemon.prototype.start = function (bReverse) {
    var bBackw = Boolean(bReverse);
    if (this.BACKW === bBackw && (this.isAtEnd() || !this.PAUSED)) { return false; }
    this.BACKW = bBackw;
    this.PAUSED = false;
    if (this.onstart) { this.onstart.call(this.owner, this.INDEX, this.length, this.BACKW); }
    this.synchronize();
    return true;
  };

  Daemon.prototype.stop = function () {
    this.pause();
    if (this.onstop) { this.onstop.call(this.owner, this.INDEX, this.length, this.BACKW); }
    delete this.INDEX;
    delete this.BACKW;
    delete this.reversals;
  };
 
 
 
      /*******************************
      *     DAEMON IS NOW READY!     *
      *******************************/
 
 
 
 
      /*******************************
      *          POLYFILLS           *
      *******************************/
 
 
 
 /*\
 |*|
 |*|  IE-specific polyfill which enables the passage of arbitrary arguments to the
 |*|  callback functions of JavaScript timers (HTML5 standard syntax).
 |*|
 |*|  https://developer.mozilla.org/en-US/docs/DOM/window.setInterval
 |*|
 |*|  Syntax:
 |*|  var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
 |*|  var timeoutID = window.setTimeout(code, delay);
 |*|  var intervalID = window.setInterval(func, delay[, param1, param2, ...]);
 |*|  var intervalID = window.setInterval(code, delay);
 |*|
 \*/

/*
  if (document.all && !window.setTimeout.isPolyfill) {
    var __nativeST__ = window.setTimeout;
    window.setTimeout = function (vCallback, nDelay) {
      var aArgs = Array.prototype.slice.call(arguments, 2);
      return __nativeST__(vCallback instanceof Function ? function () {
        vCallback.apply(null, aArgs);
      } : vCallback, nDelay);
    };
    window.setTimeout.isPolyfill = true;
  }
    
  if (document.all && !window.setInterval.isPolyfill) {
    var __nativeSI__ = window.setInterval;
    window.setInterval = function (vCallback, nDelay) {
      var aArgs = Array.prototype.slice.call(arguments, 2);
      return __nativeSI__(vCallback instanceof Function ? function () {
        vCallback.apply(null, aArgs);
      } : vCallback, nDelay);
    };
    window.setInterval.isPolyfill = true;
  }
*/

daemon-safe.js

What follows is the module which extends the Daemon constructor with a Daemon.safe sub-system. This library requires fork.js to work. The Daemon.safe constructor is as a dependent-clone of Daemon which uses a recursive invocation of the setTimeout timer rather than a single invocation of setInterval.

 /*\
 |*|
 |*|                     *******************************
 |*|                     *        daemon-safe.js       *
 |*|                     *******************************
 |*|
 |*|  ver. 1.0 rev. 1
 |*|
 |*|  fork.js - A JAVASCRIPT HIGLY SCALABLE DAEMONS MANAGER
 |*|
 |*|  https://developer.mozilla.org/en-US/docs/JavaScript/Timers/Daemons
 |*|  https://developer.mozilla.org/User:fusionchess
 |*|
 |*|  This framework is released under the GNU Public License, version 3 or later.
 |*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
 |*|
 \*/
 
"use strict";
 
 
      /**************************************
      *     THE SAFE-DAEMON SUB-SYSTEM     *
      **************************************/
 
 
 
/* The "Daemon.safe" constructor */
 
  Daemon.safe = function () { Daemon.apply(this, arguments); };
 
    /* Create the Daemon.safe.blank() constructor and the Daemon.safe.context object */
 
  Daemon.safe.blank = function () {};
  Daemon.safe.context = Daemon.safe.prototype;
  Daemon.TO_BE_DEFINED = Daemon.safe.blank.prototype; /* Make love with the GC :-) */
  Daemon.safe.blank.prototype = /* Important! */ Daemon.safe.prototype = /* Important! */ new Daemon.blank();
  Daemon.safe.prototype.constructor = Daemon.safe;
  Daemon.TO_BE_DEFINED.constructor = Daemon.safe.context.constructor = Object;
 
 
/* SYSTEM REQUIRED Daemon.safe global object methods */
 
  Daemon.safe.forceCall = function (oDmn) {
 
    oDmn.INDEX += oDmn.BACKW ? -1 : 1;
 
    var
      bBreak = oDmn.task.call(oDmn.owner, oDmn.INDEX, oDmn.length, oDmn.BACKW) === false,
      bEnd = oDmn.isAtEnd(), bInvert = oDmn.reversals > 0;
 
    if (bEnd && !bInvert || bBreak) {
      oDmn.PAUSED = true;
      return false;
    }
 
    if (bEnd && bInvert) {
      oDmn.BACKW = !oDmn.BACKW;
      oDmn.reversals--;
    }
 
    oDmn.synchronize();
 
    return true;
 
  };
 
 
/* SYSTEM NOT REQUIRED Daemon.safe global object methods */
 
  /**
  * Daemon.safe global object optional methods (shortcurts). You could safely remove all or some of
  * them, depending on your needs.
  **/
 
    /* Warnign: this method requires the global Daemon.construct() method */
  Daemon.safe.construct = Daemon.construct;
 
    /* Warnign: this method requires the global Daemon.buildAround() method */
  Daemon.safe.buildAround = Daemon.buildAround;
 
    /* Warnign: this method requires the global Daemon.incorporate() method */
  Daemon.safe.incorporate = Daemon.incorporate;
 
 
/* SYSTEM REQUIRED Daemon.safe instances methods */
 
  Daemon.safe.prototype.synchronize = function () {
    if (this.PAUSED) { return; }
    clearTimeout(this.SESSION);
    this.SESSION = setTimeout(Daemon.safe.forceCall, this.rate, this);
  };

  Daemon.safe.prototype.pause = function () {
    clearTimeout(this.SESSION);
    this.PAUSED = true;
  };

 
/* SYSTEM NOT REQUIRED Daemon.safe instances methods */

  /* [inherited from Daemon.prototype] */


 
      /*****************************************
      *     THE SAFE-DAEMON IS NOW READY!     *
      *****************************************/

daemons-methods.js

What follows is a module which collects a wide and scalable list of additional methods for instances of Daemon (and Daemon.safe). This module requires fork.js to work.  You can safely remove all or some of these methods, depending on your needs (modularity).  When a method requires the presence of another method (it is relatively rare) there is a comment which explains why. If there are not comments to that method it depends only on the base system.

 /*\
 |*|
 |*|                     *******************************
 |*|                     *       daemon-methods.js     *
 |*|                     *******************************
 |*|
 |*|  ver. 1.0 rev. 1
 |*|
 |*|  fork.js - A JAVASCRIPT HIGLY SCALABLE DAEMONS MANAGER
 |*|
 |*|  https://developer.mozilla.org/en-US/docs/JavaScript/Timers/Daemons
 |*|  https://developer.mozilla.org/User:fusionchess
 |*|
 |*|  This framework is released under the GNU Public License, version 3 or later.
 |*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
 |*|
 \*/
 
"use strict";
 
 
/* SYSTEM NOT REQUIRED Daemon instances methods */
 
    /* Movement */
 
  Daemon.prototype.syncStart = function (bReverse) {
    this.synchronize();
    if (this.start(bReverse || false)) {
      Daemon.forceCall(this);
      return true;
    }
    return false;
  };
 
  Daemon.prototype.play = function (bSync) {
    /* Warnign: this method OPTIONALLY requires the Daemon.prototype.syncStart() method */
    return this[bSync ? "start" : "syncStart"]();
  };
 
  Daemon.prototype.reversePlay = function (bSync) {
    /* Warnign: this method OPTIONALLY requires the Daemon.prototype.syncStart() method */
    return this[bSync ? "start" : "syncStart"](true);
  };
 
  Daemon.prototype.move = function (bSync, nCycles, bDirection) {
    /* Warnign: this method OPTIONALLY requires the Daemon.prototype.syncStart() method */
    if (arguments.length > 1 && !isNaN(nCycles)) { this.reversals = Number(nCycles); }
    this[bSync ? "start" : "syncStart"](arguments.length > 2 ? bDirection : this.isAtEnd() !== this.BACKW);
  };
 
  Daemon.prototype.turn = function (bSync) {
    /* Warnign: this method OPTIONALLY requires the Daemon.prototype.syncStart() method */
    this[bSync ? "start" : "syncStart"](!this.BACKW);
  };
 
    /* Settings tools */
 
  Daemon.prototype.makeLoop = function () {
    this.reversals = Infinity;
  };
 
  Daemon.prototype.unmakeLoop = function () {
    this.reversals = 0;
  };
 
  Daemon.prototype.setRate = function (vTo) {
    var nRate = Number(vTo);
    if (!isFinite(nRate) || nRate < 1) { return; }
    this.rate = nRate;
    this.synchronize();
  };
 
  Daemon.prototype.forcePosition = function (vTo) {
    if (isFinite(vTo)) { this.INDEX = Math.round(Math.abs(vTo)); }
  };
 
  Daemon.prototype.getDuration = function () {
    return this.rate * this.length;
  };
 
  Daemon.prototype.getDirection = function () {
    return this.isAtEnd() !== this.BACKW;
  };
 
  Daemon.prototype.getPosition = function () {
    return this.INDEX;
  };
 
    /* Instantaneous movement (synchronous). */
 
  Daemon.prototype.makeSteps = function (nHowMany, bReverse, bForce) {
    if (nHowMany === 0) { return true; }
    if (isNaN(nHowMany)) { return false; }
    var nIdx = 0, nLen = Math.round(Math.abs(nHowMany)), bContinue = true, bBackw = nHowMany > 0 === Boolean(bReverse);
    this.BACKW = bBackw;
    for (nIdx; nIdx < nLen && bContinue; nIdx++) {
      if (this.BACKW === bBackw && this.isAtEnd()) {
        if (this.reversals > 0) { this.BACKW = bBackw = !this.BACKW; }
        else { break; }
      }
      bContinue = Daemon.forceCall(this) || bForce;
    }
    return nIdx === nLen;
  };
 
  Daemon.prototype.skipTo = function (nIdx, bForce) {
    /* Warnign: this method requires the Daemon.prototype.makeSteps() method */
    if (nIdx === this.INDEX) { return; }
    if (isFinite(this.length) && nIdx < 0 || nIdx > this.length) { return; }
 
    var
      bDirection = (this.INDEX !== 0 && this.INDEX !== this.length) === this.BACKW,
      bSuccess = this.makeSteps(this.INDEX - nIdx, true, bForce);
 
    if (this.INDEX !== 0 && this.INDEX !== this.length) { this.BACKW = bDirection; }
    return bSuccess;
  };
 
  Daemon.prototype.skipFor = function (nDelta, bForce) {
    /* Warnign: this method requires the Daemon.prototype.makeSteps() method */
    return this.makeSteps(nDelta, this.isAtEnd() !== this.BACKW, bForce);
  };
 
  Daemon.prototype.close = function (bReverse, bForce) {
    /* Warnign: this method requires the Daemon.prototype.makeSteps() method */
    if (!isFinite(this.length)) { return false; }
    this.pause();
    this.reversals = 0;
    return this.makeSteps(bReverse ? this.INDEX : this.length - this.INDEX, bReverse, bForce);
  };
 
  Daemon.prototype.reclose = function (bForce) {
    /* Warnign: this method requires the Daemon.prototype.makeSteps() and Daemon.prototype.close() methods */
    return this.close(this.isAtEnd() !== this.BACKW, bForce || false);
  };
 
  /* Others */
 
  Daemon.prototype.restart = function () {
    this.stop();
    this.start();
  };
 
  Daemon.prototype.loopUntil = function (vDate) {
    if (!isFinite(this.length)) { return; }
    var nTime = vDate.constructor === Date ? vDate.getTime() : isNaN(vDate) ? Date.parse(vDate) : vDate;
    if (isFinite(nTime) && nTime > Date.now()) {
      this.reversals = Math.floor((nTime - Date.now() - (this.BACKW ? this.INDEX : this.length - this.INDEX) * this.rate) / (this.length * this.rate));
      this.start(this.isAtEnd() !== this.BACKW);
    }
  };
 
  Daemon.prototype.spread = function (nTime) {
    if (!isFinite(this.length)) { throw new TypeError("Daemon.prototype.spread - the length is not a finite number. Use Daemon.prototype.adaptLength()."); }
    if (nTime > 0) {
      this.rate = Math.floor(nTime / this.length);
      this.synchronize();
    }
    return this.rate;
  };
 
  Daemon.prototype.adaptLength = function (nTime) {
    this.length = Math.floor(nTime / this.rate);
    return this.length;
  };
 
  Daemon.prototype.playUntil = function (vDate) {
    var nTime = vDate.constructor === Date ? vDate.getTime() : isNaN(vDate) ? Date.parse(vDate) : vDate;
    if (isFinite(nTime) && nTime > Date.now()) {
      this.length = Math.floor((nTime - Date.now()) / this.rate) + this.INDEX;
      this.pause();
      this.start();
    }
    return this.length;
  };

Manual

The constructor

Syntax

var myDaemon = new Daemon(thisObject, callback[, rate[, length[, init[, onstart]]]]);

Description

Constructs a JavaScript Object containing all informations needed by an animation (like the this object, the callback function, the length, the frame-rate, the number of cycles, the init and the onstart functions).

Arguments

thisObject
The this object on which will be called the callback function. It can be an object or null. If is null, the this object will point to the global Deamon.context object (see below).
callback
The function which will be invoked repeatedly. It will be called with three parameters: index (the iterative index of each invocation), length (the number of total invocations assigned to the daemon - finite or Infinity) and backwards (a boolean expressing whether the process is going backwards or not). It will be something like callback.call(thisObject, index, length, backwards). If the callback function returns a false value the daemon will be paused.
rate [optional]
The time lapse (in number of milliseconds) between each invocation. The default value is 100.
length [optional]
The total number of invocations. It can be a positive integer or Infinity. The default value is Infinity.
init [optional]
The function which will be synchronously invoked once during the creation of the daemon and then assigned to the onstop property. It will be called with the same three arguments of the callback function. They will also have the same values of the last invocation of the callback function.
onstart [optional]
The function which will be synchronously invoked on whenever the start event occurs. It will be assigned to the onstart property. It will be called with three arguments: index (the iterative index of each invocation), length (the number of total invocations assigned to the daemon - finite or Infinity) and backwards (a boolean expressing whether the process is going backwards or not).

Daemon global object properties

Daemon.context
An empty object used as default this object when the thisObject is not specified during the construction of the daemon. If you want your callback function to be invoked with a null this object you have to manually set the owner property to null.

Daemon global object methods

Daemon.forceCall(daemonInstance)
Forces a callback to the daemonInstance.task function regardless of the fact that the end has been reached or not. In any case the internal INDEX property will be increased/decreased (depending on the actual direction of the daemon).
Daemon.construct(arrayOfArguments)
Returns a new daemon constructed upon an array of arguments. It is very similar to the Function.prototype.apply() method.
Daemon.buildAround(context[, rate[, length]])
Returns a new daemon built around a context object. The context object must cointain *at least* a perform property pointing to what you want to be the callback function of the daemon. It can also optionally contain a create and a prepare properties pointing respectively to the two functions you want to be the init and onstart functions of Daemon constructor's arguments. The context object will be also the this object of your callback function. So you can populate it with all your custom properties. and methods. The only required one property is perform.
Sample usage:
var myDaemon = Daemon.buildAround({
	"create": function () { [custom code] },  // optional
	"prepare": function () { [custom code] },  // optional
	"perform": function () { [custom code] },  // required
	"customProperty": [custom value],
	"myCustomMethod": function () { [custom code] },
	"anotherCustomProperty": [custom value],
	"etc.": "etc."
}, 200, 30);
Daemon.incorporate(function)
The function.prototype property will replaced with a new Daemon() object. The old replaced prototype will be preserved within a new property of the new function.prototype object named legacy.

Other constructors

Daemon.blank()
Constructs a new instance of Daemon without own properties. This constructor is useful in order to create your own *MySomeDaemon* constructors through the MySomeDaemon.prototype = new Daemon.blank(); assignment.
Daemon.safe() [optional module daemon-safe.js]
Syntax
var myDaemon = new Daemon.safe(thisObject, callback[, rate[, length[, init[, onstart]]]]);
Description

Daemon.safe is a clone of the Daemon constructor based on recursive invocations of setTimeout rather than on a single invocation of setInterval. See the daemon-safe.js module for details.

Note: The Daemon.safe constructor is not part of the base system.
Daemon.safe.blank() [optional module daemon-safe.js]

The same as for Daemon.blank, but applied to the Daemon.safe constructor.

Note: The Daemon.safe constructor is not part of the base system.

Daemon instances properties

myDaemon.owner
The this object on which is executed the daemon (read/write). It can be an object or null. Its default value is Daemon.context.
myDaemon.task
The function which will be repeatedly invoked (read/write). It will be called with three arguments: index (the iterative index of each invocation), length (the number of total invocations assigned to the daemon - finite or Infinity) and backwards (a boolean expressing whether the process is going backwards or not). See above. If the myDaemon.task function returns a false value the daemon will be paused.
myDaemon.rate
The time lapse (in number of milliseconds) between each invocation (read/write).
myDaemon.length
The total number of invocations. It can be a positive integer or Infinity (read/write).
myDaemon.reversals
The number of times the daemon must be restarted (read/write). Set it to Infinity for a “loop mode”.
myDaemon.onstart
The start listener (read/write). It will be called with three arguments: index (the iterative index of each invocation), length (the number of total invocations assigned to the daemon - finite or Infinity) and backwards (a boolean expressing whether the process is going backwards or not).
myDaemon.onstop

The stop listener (read/write). It will be called with three arguments: index (the iterative index of each invocation), length (the number of total invocations assigned to the daemon - finite or Infinity) and backwards (a boolean expressing whether the process is going backwards or not).

Note: The stop() method is not part of the base system.

Daemon instances methods

myDaemon.isAtEnd()
Returns a boolean expressing whether the daemon is at the start/end position or not.
myDaemon.synchronize()
Synchronize the timer of a started daemon with the time of invocation of myDaemon.synchronize(). If the rate property has been changed the daemon will be updated with the new rate value.
myDaemon.pause()
Pauses the daemon.
myDaemon.start([backwards])
Starts the daemon forward (index of each invocation increasing) or backwards (index decreasing).
myDaemon.stop()
Stops the daemon. All original properties will be restored. If it exists a stop listener it will be called with three arguments: index (the iterative index of each invocation), length (the number of total invocations assigned to the daemon - finite or Infinity) and backwards (a boolean expressing whether the process is going backwards or not).

Additional instances methods [optional module daemons-methods.js]

myDaemon.syncStart([backwards])
Starts the daemon with the first callback synchronous.
myDaemon.play([synchronous])
Starts the daemon forward. If the daemon was running in the same direction nothing will happen. If the argument is true the first callback will be synchronous.
myDaemon.reversePlay([synchronous])
Starts the daemon backwards. If the daemon was running in the same direction nothing will happen. If the argument is true the first callback will be synchronous.
myDaemon.move([synchronous[, reversals[, backwards]]])
Starts a daemon synchronously or not. If the reversals argument is specified the myDaemon.reversals property will be setted on it. If the backwards argument is specified the daemon will move forward (false) or backwards (true). If it is not specified the daemon will start in the same direction in which it has been left. If the daemon was running in the same direction, only the reversals property will be possibly updated.
myDaemon.turn()
Inverts the direction of the daemon. The reversals property will not be decreased.
myDaemon.makeLoop()
Sets the reversals property equal to Infinity.
myDaemon.unmakeLoop()
Sets the reversals property equal to 0.
myDaemon.setRate(milliseconds)
Sets the time lapse between calls (in milliseconds). If the daemon is running it will be immediately updated with the new property.
myDaemon.forcePosition(index)
Sets the internal INDEX property equal to the index argument without any kind of control about the range.
myDaemon.getDuration()
Returns the duration of the daemon in milliseconds.
myDaemon.getPosition()
Returns the internal INDEX property.
myDaemon.makeSteps(howMany[, backwards[, force]])
Calls synchronously the callback function howMany times. Forwards or backwards. If the force argument is setted to true the possible return false of the callback function will be ignored.
myDaemon.skipTo(index[, force])
Calls synchronously the callback function the number of times needed to reach the index position. If the force argument is setted to true the possible return false of the callback function will be ignored.
myDaemon.skipFor(delta[, force])
Calls synchronously the callback function howMany times in the same direction in which it was oriented. If the force argument is setted to true the possible return false of the callback function will be ignored.
myDaemon.close([backwards, force])
Closes the daemon, doing synchronously all pending operations forward (index of each invocation increasing) or backwards (index decreasing). If the force argument is setted to true the possible return false of the callback function will be ignored.
myDaemon.reclose([force])
Closes the daemon, doing synchronously all pending operations in the same direction in which is oriented the daemon. If the force argument is setted to true the possible return false of the callback function will be ignored.
myDaemon.restart()
Stops and restarts the daemon.
myDaemon.loopUntil(date)
Sets the reversals property in function of a future date. The date argument can be a Date object, a string expressing the date in GMTString format, or a number expressing the number of milliseconds since January 1, 1970, 00:00:00 UTC.
myDaemon.spread(milliseconds)
Sets the the total duration of the daemon in milliseconds. Only the rate property will be modified.
myDaemon.adaptLength(milliseconds)
Sets the internal length property equal to milliseconds / myDaemon.rate.
myDaemon.playUntil(date)
Starts the daemon forward and sets the the total duration of it in function of a future date. The date argument can be a Date object, a string expressing the date in GMTString format, or a number expressing the number of milliseconds since January 1, 1970, 00:00:00 UTC. Only the length property will be modified.

Examples

Example #1: A standard instantiation – new Daemon()

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>new Daemon(&hellip;)</title>
<script type="text/javascript" src="fork.js"></script>
<script type="text/javascript" src="daemons-methods.js"></script>
<script type="text/javascript">
 
function perform (nIndex, nLength, bBackw) {
  // http://tyleregeto.com/text-animation-in-javascript
  for (var oLetter, nLetter = 0; nLetter < aLetters.length; nLetter++) {
    oLetter = aLetters[nLetter];
    var nDist = nMaxDist - nMaxDist * nIndex / nLength;
    oLetter.pos += 0.08;
    oLetter.elem.style.top = Math.sin(oLetter.pos) * nDist + "px";
    oLetter.elem.style.left = Math.cos(oLetter.pos) * nDist * 5 + "px";
  }
}
 
function prepare () {
  // build letters list
  // http://tyleregeto.com/text-animation-in-javascript
  this.textContent = "";
  aLetters.length = 0;  
  for (var oSpan, oLetter, nLetter = 0, nLen = sText.length; nLetter < nLen; nLetter++) {
    oSpan = document.createElement("span");
    oSpan.textContent = sText[nLetter];
    oLetter = { "elem": oSpan, "parent": this };
    aLetters.push(oLetter);
    oLetter.pos = Math.random() * 50;
    oLetter.elem.style.position = "relative";
    this.appendChild(oSpan);
  }
}
 
var
  nMaxDist = 25, aLetters = [], sText = "Do you feel lucky, punk?",
  oRecompose = new Daemon(document.createElement("p"), perform, 33, 30, prepare);
 
onload = function () {
  oRecompose.owner.id = "perform-me";
  document.body.appendChild(oRecompose.owner);
  oRecompose.play();
};
 
</script>
 
<style type="text/css">
body {
  font-family: monospace, sans-serif;
  background: #DDDDDD;
  overflow: hidden;
}
 
#perform-me {
  margin: 50px;
  font-size: 20px;
  line-height: 20px;
}
</style>
</head>
 
<body>
 
<h1>new Daemon(<em>@thisObject</em>, <em>@callback</em>[, <em>@rate</em>, <em>@length</em>, <em>@init</em>, <em>@onstart</em>])</h1>
 
<p><button onclick="oRecompose.skipTo(11);">skipTo(11)</button>
<button onclick="oRecompose.makeSteps(29);">makeSteps(29)</button>
<button onclick="oRecompose.fixPosition(-13);">fixPosition(-13)</button>
<button onclick="oRecompose.play();">play</button>
<button onclick="oRecompose.turn();">turn</button>
<button onclick="oRecompose.pause();">pause</button>
<button onclick="oRecompose.reversePlay();">reversePlay</button>
<button onclick="oRecompose.reversals = 2;alert('changed');">two reversals</button>
<button onclick="oRecompose.makeLoop();alert('changed');">makeLoop</button>
<button onclick="oRecompose.unmakeLoop();alert('changed');">unmakeLoop</button>
<button onclick="oRecompose.close();">close</button>
<button onclick="oRecompose.reclose();">reclose</button><br />
frame rate: <input type="text" id="vello" value="33" style="width: 40px;" onkeypress="return event.charCode===0||/\d/.test(String.fromCharCode(event.charCode));" onkeyup="if(isFinite(this.value)&&Number(this.value)>0){oRecompose.setRate(this.value);}" /></p>
 
</body>
</html>

Example #2: A practical instantiation – Daemon.buildAround()

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Daemon.buildAround(&hellip;)</title>
<script type="text/javascript" src="fork.js"></script>
<script type="text/javascript" src="daemons-methods.js"></script>
<script type="text/javascript">
 
 /*\
 |*|
 |*|  :: Daemon.buildAround(@context[, @rate, @length]) ::
 |*|
 |*|  Returns a new daemon built around a @context object. The @context object must cointain *at least*
 |*|  a "perform" property pointing to what you want to be the @callback function of the daemon.
 |*|  It can also optionally contain a "create" and a "prepare" properties pointing respectively to the
 |*|  two functions you want to be the @init and @onstart functions of Daemon constructor's arguments.
 |*|  The @context object will be also the *this* object of your callback function. So you can populate
 |*|  it with any custom properties and methods. The only required one property is "perform".
 |*|     
 |*|    Sample usage:
 |*|
 |*|      var myDaemon = Daemon.buildAround({
 |*|        "customProperty": [custom value],
 |*|        "myCustomMethod": function () { [custom code] },
 |*|        "anotherCustomProperty": [custom value],
 |*|        "etc.": "etc."
 |*|        "create": function () { [custom code] },  // optional
 |*|        "prepare": function () { [custom code] },  // optional
 |*|        "perform": function () { [custom code] },  // required
 |*|      }, 200, 30);
 |*|
 \*/
 
var sText = "Do you feel lucky, punk?", oUnhide = Daemon.buildAround({
  // http://tyleregeto.com/text-animation-in-javascript
  "letters": [],
  "numletters": 0,
  "clock": 0,
  "interval": 0.0,
  "delta": 33,
  "letters": [],
  "pool": ["0","1","2","3","4","5","6","7","8","9"],
  "target": document.createElement("p"),
  "create": function () {
    // build letters list
    this.target.textContent = "";
    this.letters.length = 0;
    for (var oSpan, oLetter, nLetter = 0, nLen = sText.length; nLetter < nLen; nLetter++) {
      oSpan = document.createElement("span");
      oSpan.textContent = sText[nLetter];
      oLetter = { "elem": oSpan, "parent": this.target };
      this.letters.push(oLetter);
      oLetter.index = this.numletters;
      oLetter.elem.style.position = "relative";
      oLetter.val = oLetter.elem.textContent;
      this.numletters++;
      this.target.appendChild(oSpan);
    }
  },
  "perform": function (nIndex, nLength, bBackw) {
    for (var oLetter, nLetter = 0; nLetter < this.letters.length; nLetter++) {
      oLetter = this.letters[nLetter];
      if (nLength < nIndex && this.clock + this.delta < this.interval) {
        clock += this.delta;
        return;
      }
      this.clock = 0;
      oLetter.elem.textContent = nIndex / nLength - oLetter.index / this.numletters >= 0 ?
        oLetter.val
        : this.pool[parseInt(Math.random() * this.pool.length)];
    }
  }
}, 33, 30);
 
onload = function () {
  oUnhide.owner.target.id = "animate-me";
  document.body.appendChild(oUnhide.owner.target);
  oUnhide.play();
};
 
</script>
 
<style type="text/css">
body {
  font-family: monospace, sans-serif;
  background: #DDDDDD;
  overflow: hidden;
}
 
#animate-me {
  margin: 50px;
  font-size: 20px;
  line-height: 20px;
}
</style>
</head>
 
<body>
 
<h1>Daemon.buildAround()</h1>
 
<p><button onclick="oUnhide.skipTo(11);">skipTo(11)</button>
<button onclick="oUnhide.makeSteps(29);">makeSteps(29)</button>
<button onclick="oUnhide.fixPosition(-13);">fixPosition(-13)</button>
<button onclick="oUnhide.play();">play</button>
<button onclick="oUnhide.turn();">turn</button>
<button onclick="oUnhide.pause();">pause</button>
<button onclick="oUnhide.reversePlay();">reversePlay</button>
<button onclick="oUnhide.reversals = 2;alert('changed');">two reversals</button>
<button onclick="oUnhide.makeLoop();alert('changed');">makeLoop</button>
<button onclick="oUnhide.unmakeLoop();alert('changed');">unmakeLoop</button>
<button onclick="oUnhide.close();">close</button>
<button onclick="oUnhide.reclose();">reclose</button><br />
frame rate: <input type="text" id="vello" value="33" style="width: 40px;" onkeypress="return event.charCode===0||/\d/.test(String.fromCharCode(event.charCode));" onkeyup="if(isFinite(this.value)&&Number(this.value)>0){oUnhide.setRate(this.value);}" /></p>
 
</body>
</html>

Example #3: A safe (without setInterval) instantiation – new Daemon.safe()

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>new Daemon.safe(&hellip;)</title>
<script type="text/javascript" src="fork.js"></script>
<script type="text/javascript" src="daemon-safe.js"></script>
<script type="text/javascript" src="daemons-methods.js"></script>
<script type="text/javascript">
 
function perform (nIndex, nLength, bBackw) {
  // http://tyleregeto.com/text-animation-in-javascript
  for (var oLetter, nLetter = 0; nLetter < aLetters.length; nLetter++) {
    oLetter = aLetters[nLetter];
    var nDist = nMaxDist - nMaxDist * nIndex / nLength;
    oLetter.pos += 0.08;
    oLetter.elem.style.top = Math.sin(oLetter.pos) * nDist + "px";
    oLetter.elem.style.left = Math.cos(oLetter.pos) * nDist * 5 + "px";
  }
}
 
function prepare () {
  // build letters list
  // http://tyleregeto.com/text-animation-in-javascript
  this.textContent = "";
  aLetters.length = 0;  
  for (var oSpan, oLetter, nLetter = 0, nLen = sText.length; nLetter < nLen; nLetter++) {
    oSpan = document.createElement("span");
    oSpan.textContent = sText[nLetter];
    oLetter = { "elem": oSpan, "parent": this };
    aLetters.push(oLetter);
    oLetter.pos = Math.random() * 50;
    oLetter.elem.style.position = "relative";
    this.appendChild(oSpan);
  }
}
 
var
  nMaxDist = 25, aLetters = [], sText = "Do you feel lucky, punk?",
  oRecompose = new Daemon.safe(document.createElement("p"), perform, 33, 30, prepare);
 
onload = function () {
  oRecompose.owner.id = "perform-me";
  document.body.appendChild(oRecompose.owner);
  oRecompose.play();
};
 
</script>
 
<style type="text/css">
body {
  font-family: monospace, sans-serif;
  background: #DDDDDD;
  overflow: hidden;
}
 
#perform-me {
  margin: 50px;
  font-size: 20px;
  line-height: 20px;
}
</style>
</head>
 
<body>
 
<h1>new Daemon.safe(<em>@thisObject</em>, <em>@callback</em>[, <em>@rate</em>, <em>@length</em>, <em>@init</em>, <em>@onstart</em>])</h1>
 
<p><button onclick="oRecompose.skipTo(11);">skipTo(11)</button>
<button onclick="oRecompose.makeSteps(29);">makeSteps(29)</button>
<button onclick="oRecompose.fixPosition(-13);">fixPosition(-13)</button>
<button onclick="oRecompose.play();">play</button>
<button onclick="oRecompose.turn();">turn</button>
<button onclick="oRecompose.pause();">pause</button>
<button onclick="oRecompose.reversePlay();">reversePlay</button>
<button onclick="oRecompose.reversals = 2;alert('changed');">two reversals</button>
<button onclick="oRecompose.makeLoop();alert('changed');">makeLoop</button>
<button onclick="oRecompose.unmakeLoop();alert('changed');">unmakeLoop</button>
<button onclick="oRecompose.close();">close</button>
<button onclick="oRecompose.reclose();">reclose</button><br />
frame rate: <input type="text" id="vello" value="33" style="width: 40px;" onkeypress="return event.charCode===0||/\d/.test(String.fromCharCode(event.charCode));" onkeyup="if(isFinite(this.value)&&Number(this.value)>0){oRecompose.setRate(this.value);}" /></p>
 
</body>
</html>

Example #4: A practical and safe (without setInterval) instantiation – Daemon.safe.buildAround()

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Daemon.safe.buildAround(&hellip;)</title>
<script type="text/javascript" src="fork.js"></script>
<script type="text/javascript" src="daemon-safe.js"></script>
<script type="text/javascript" src="daemons-methods.js"></script>
<script type="text/javascript">
 
 /*\
 |*|
 |*|  :: Daemon.safe.buildAround(@context[, @rate, @length]) ::
 |*|
 |*|  Returns a new daemon built around a @context object. The @context object must cointain *at least*
 |*|  a "perform" property pointing to what you want to be the @callback function of the daemon.
 |*|  It can also optionally contain a "create" and a "prepare" properties pointing respectively to the
 |*|  two functions you want to be the @init and @onstart functions of Daemon constructor's arguments.
 |*|  The @context object will be also the *this* object of your callback function. So you can populate
 |*|  it with any custom properties and methods. The only required one property is "perform".
 |*|     
 |*|    Sample usage:
 |*|
 |*|      var myDaemon = Daemon.safe.buildAround({
 |*|        "customProperty": [custom value],
 |*|        "myCustomMethod": function () { [custom code] },
 |*|        "anotherCustomProperty": [custom value],
 |*|        "etc.": "etc."
 |*|        "create": function () { [custom code] },  // optional
 |*|        "prepare": function () { [custom code] },  // optional
 |*|        "perform": function () { [custom code] },  // required
 |*|      }, 200, 30);
 |*|
 \*/
 
var sText = "Do you feel lucky, punk?", oUnhide = Daemon.safe.buildAround({
  // http://tyleregeto.com/text-animation-in-javascript
  "letters": [],
  "numletters": 0,
  "clock": 0,
  "interval": 0.0,
  "delta": 33,
  "letters": [],
  "pool": ["0","1","2","3","4","5","6","7","8","9"],
  "target": document.createElement("p"),
  "create": function () {
    // build letters list
    this.target.textContent = "";
    this.letters.length = 0;
    for (var oSpan, oLetter, nLetter = 0, nLen = sText.length; nLetter < nLen; nLetter++) {
      oSpan = document.createElement("span");
      oSpan.textContent = sText[nLetter];
      oLetter = { "elem": oSpan, "parent": this.target };
      this.letters.push(oLetter);
      oLetter.index = this.numletters;
      oLetter.elem.style.position = "relative";
      oLetter.val = oLetter.elem.textContent;
      this.numletters++;
      this.target.appendChild(oSpan);
    }
  },
  "perform": function (nIndex, nLength, bBackw) {
    for (var oLetter, nLetter = 0; nLetter < this.letters.length; nLetter++) {
      oLetter = this.letters[nLetter];
      if (nLength < nIndex && this.clock + this.delta < this.interval) {
        clock += this.delta;
        return;
      }
      this.clock = 0;
      oLetter.elem.textContent = nIndex / nLength - oLetter.index / this.numletters >= 0 ?
        oLetter.val
        : this.pool[parseInt(Math.random() * this.pool.length)];
    }
  }
}, 33, 30);
 
onload = function () {
  oUnhide.owner.target.id = "animate-me";
  document.body.appendChild(oUnhide.owner.target);
  oUnhide.play();
};
 
</script>
 
<style type="text/css">
body {
  font-family: monospace, sans-serif;
  background: #DDDDDD;
  overflow: hidden;
}
 
#animate-me {
  margin: 50px;
  font-size: 20px;
  line-height: 20px;
}
</style>
</head>
 
<body>
 
<h1>Daemon.safe.buildAround()</h1>
 
<p><button onclick="oUnhide.skipTo(11);">skipTo(11)</button>
<button onclick="oUnhide.makeSteps(29);">makeSteps(29)</button>
<button onclick="oUnhide.fixPosition(-13);">fixPosition(-13)</button>
<button onclick="oUnhide.play();">play</button>
<button onclick="oUnhide.turn();">turn</button>
<button onclick="oUnhide.pause();">pause</button>
<button onclick="oUnhide.reversePlay();">reversePlay</button>
<button onclick="oUnhide.reversals = 2;alert('changed');">two reversals</button>
<button onclick="oUnhide.makeLoop();alert('changed');">makeLoop</button>
<button onclick="oUnhide.unmakeLoop();alert('changed');">unmakeLoop</button>
<button onclick="oUnhide.close();">close</button>
<button onclick="oUnhide.reclose();">reclose</button><br />
frame rate: <input type="text" id="vello" value="33" style="width: 40px;" onkeypress="return event.charCode===0||/\d/.test(String.fromCharCode(event.charCode));" onkeyup="if(isFinite(this.value)&&Number(this.value)>0){oUnhide.setRate(this.value);}" /></p>
 
</body>
</html>

See also

Revision Source

<p>In Computer science a <em>daemon</em> is a task that runs as a background process, rather than being under the direct control of an interactive user. In JavaScript programming language, are called <em>daemons</em> all processes created by JavaScript timers or by a <a href="https://developer.mozilla.org/en-US/docs/DOM/Worker" title="/en-US/docs/DOM/Worker"><code>Worker</code></a> instantiation. Here are some code snippets which simplify and abstract the management of daemons.</p>
<p>The following <em>daemons management framework</em> is <strong>the major version of <a href="/en-US/docs/DOM/window.setInterval#A_little_framework" title="/en-US/docs/DOM/window.setInterval#A_little_framework">setInterval – <em>A little framework</em></a></strong>.</p>
<h2 id="Introduction">Introduction</h2>
<p>Sometimes a page uses dozens and dozens of animations. In such a condition is difficult and unnatural to keep track of all events started and then to stop them when appropriate through the <code>clearTimeout()</code> function. A possible approach to solve this problem is to nest all the informations needed by each animation to start, stop, etc. etc. in different objects (<em>daemons</em>) and then to create a constructor for such class of objects (<code>Daemon</code>) in order to standardize and simplify the instantiation of them.</p>
<div class="note">
  <strong>Note:</strong> A minimalistic version of it (<code><em>MiniDaemon</em></code>) is published <strong><a href="/en-US/docs/DOM/window.setInterval#A_little_framework" title="/en-US/docs/DOM/window.setInterval#A_little_framework">here</a></strong>. This more complex version of it is nothing but a big and scalable collection of methods for the <code><em>Daemon</em></code> constructor. But the <code><em>Daemon</em></code> constructor itself is nothing but a clone of <code><em>MiniDaemon</em></code> with an added support for <em>init</em> and <em>onstart</em> functions declarable during the instantiation of the <code><em>daemon</em></code>. <strong>So the <code><em>MiniDaemon</em></code> framework will remain the recommended way for simple animations</strong>, because <code><em>Daemon</em></code> without its collection of methods is essentially a clone of it.</div>
<p>The architecture of the <code>Daemon</code> constructor explicitly avoids the use of closures. It also offers an alternative way to pass the <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this" title="en-US/docs/JavaScript/Reference/Operators/this"><code>this</code></a> object to the callback functions (see <a href="https://developer.mozilla.org/en-US/docs/DOM/window.setInterval#The_.22this.22_problem" title="The 'this' problem">The "this" problem</a> for details).</p>
<p>Advantages of this approch:</p>
<ul>
  <li>abstraction,</li>
  <li>passage of <a href="/en-US/docs/JavaScript/Reference/Operators/this" title="en-US/docs/JavaScript/Reference/Operators/this"><code>this</code></a> object to JavaScript timers (both <a href="https://developer.mozilla.org/en-US/docs/DOM/window.setInterval" title="https://developer.mozilla.org/en-US/docs/DOM/window.setInterval"><code>setInterval</code></a> and <a href="https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout" title="https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout"><code>setTimeout</code></a>),</li>
  <li>optimisation (avoiding <a href="/en-US/docs/JavaScript/Guide/Closures" title="/en-US/docs/JavaScript/Guide/Closures">closures</a>),</li>
  <li>modularity.</li>
</ul>
<h2 id="The_code">The code</h2>
<p>The code of this framework is splitted into three files:</p>
<ul>
  <li><strong>fork.js</strong> (the core),</li>
  <li><strong>daemon-safe.js</strong> (an extension of the core which <em>adds</em> a replacement of <a href="https://developer.mozilla.org/en-US/docs/DOM/window.setInterval" title="https://developer.mozilla.org/en-US/docs/DOM/window.setInterval"><code>setInterval</code></a> with a recursive invocation of <a href="https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout" title="https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout"><code>setTimeout</code></a>),</li>
  <li><strong>daemons-methods.js</strong> (a wide and highly scalable collection of methods).</li>
</ul>
<p>The only indipendent module is <strong>fork.js</strong>: both <strong>daemon-safe.js</strong> module and <strong>daemons-methods.js</strong> module require <strong>fork.js</strong> to work.</p>
<h4 id="About_the_.E2.80.9Ccallback_arguments.E2.80.9D_polyfill">About the <a href="/en-US/docs/DOM/window.setInterval#Callback_arguments" title="/en-US/docs/DOM/window.setInterval#Callback_arguments">“callback arguments” polyfill</a></h4>
<p>In order to make this framework compatible with Internet Explorer (which doesn't support <a href="/en-US/docs/DOM/window.setInterval#Callback_arguments" title="/en-US/docs/DOM/window.setInterval#Callback_arguments">sending additional parameters to timers' callback function</a>, neither with <code>setTimeout()</code> or <code>setInterval()</code>) we included <a href="/en-US/docs/DOM/window.setInterval#Callback_arguments" title="/en-US/docs/DOM/window.setInterval#Callback_arguments">the <em>IE-specific</em> compatibility code</a> (commented code), which enables the HTML5 standard parameters passage functionality in that browser for both timers (polyfill), at the end of the <strong>fork.js</strong> module.</p>
<h3 id="fork.js">fork.js</h3>
<p>What follows is the module which declare the <code>Daemon</code> constructor (the core of this framework). The <code>Daemon</code> constructor itself is nothing but a clone of <a href="/en-US/docs/DOM/window.setInterval#A_little_framework" title="/en-US/docs/DOM/window.setInterval#A_little_framework">the little framework <code>MiniDaemon</code></a> with an added support for <code>init</code> and <code>onstart</code> functions (declarable during the instantiation of the daemon). <strong>So the <code>MiniDaemon</code> framework will remain the recommended way for simple animations</strong>, because <code>Daemon</code> without its collection of methods is essentially a clone of it.</p>
<div style="height: 400px; margin-bottom: 12px; overflow: auto;">
  <pre class="brush: js">
&nbsp;/*\
&nbsp;|*|
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *******************************
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fork.js&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *******************************
&nbsp;|*|
&nbsp;|*|&nbsp; ver. 1.0 rev. 1
&nbsp;|*|
&nbsp;|*|&nbsp; fork.js - A JAVASCRIPT HIGLY SCALABLE DAEMONS MANAGER.
&nbsp;|*|
&nbsp;|*|&nbsp; https://developer.mozilla.org/en-US/docs/JavaScript/Timers/Daemons
&nbsp;|*|&nbsp; https://developer.mozilla.org/User:fusionchess
&nbsp;|*|
&nbsp;|*|&nbsp; This framework is released under the GNU Public License, version 3 or later.
&nbsp;|*|&nbsp; http://www.gnu.org/licenses/gpl-3.0-standalone.html
&nbsp;|*|
&nbsp;\*/
&nbsp;
"use strict";
&nbsp;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /****************************
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp; THE DAEMON SYSTEM&nbsp;&nbsp;&nbsp;&nbsp; *
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ****************************/
&nbsp;
&nbsp;
&nbsp;
/* The global "Daemon" constructor */
&nbsp;
&nbsp; function Daemon (oOwner, fTask, nRate, nLen, fInit, fOnstart) {
&nbsp;&nbsp;&nbsp; if (!(this &amp;&amp; this instanceof Daemon)) { return; }
&nbsp;&nbsp;&nbsp; if (arguments.length &lt; 2) { throw new TypeError("Daemon - not enough arguments"); }
&nbsp;&nbsp;&nbsp; if (oOwner) { this.owner = oOwner };
&nbsp;&nbsp;&nbsp; this.task = fTask;
&nbsp;&nbsp;&nbsp; if (isFinite(nRate) &amp;&amp; nRate &gt; 0) { this.rate = Math.floor(nRate); }
&nbsp;&nbsp;&nbsp; if (nLen &gt; 0) { this.length = Math.floor(nLen); }
&nbsp;&nbsp;&nbsp; if (fOnstart) { this.onstart = fOnstart; }
&nbsp;&nbsp;&nbsp; if (fInit) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.onstop = fInit;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fInit.call(oOwner, this.INDEX, this.length, this.BACKW);
&nbsp;&nbsp;&nbsp; }
&nbsp; }
&nbsp;
&nbsp;&nbsp;&nbsp; /* Create the Daemon.blank() constructor and the global Daemon.context object */
&nbsp;
&nbsp; Daemon.blank = function () {};
&nbsp; Daemon.context = Daemon.blank.prototype; /* Make love with the GC :-) */
&nbsp; Daemon.blank.prototype = /* Important! */ Daemon.prototype;
&nbsp; Daemon.context.constructor = Object;
&nbsp;
&nbsp;&nbsp;&nbsp; /* These properties can be manually reconfigured after the creation of the daemon */
&nbsp;
&nbsp; Daemon.prototype.owner = Daemon.context;
&nbsp; Daemon.prototype.task = null;
&nbsp; Daemon.prototype.rate = 100;
&nbsp; Daemon.prototype.length = Infinity;
&nbsp; Daemon.prototype.reversals = 0;
&nbsp; Daemon.prototype.onstart = null;
&nbsp; Daemon.prototype.onstop = null;
&nbsp;
&nbsp;&nbsp;&nbsp; /* These properties should be read-only after the creation of the daemon */
&nbsp;
&nbsp; Daemon.prototype.SESSION = -1;
&nbsp; Daemon.prototype.INDEX = 0;
&nbsp; Daemon.prototype.PAUSED = true;
&nbsp; Daemon.prototype.BACKW = true;
&nbsp;
&nbsp;
/* SYSTEM REQUIRED Daemon global object methods */
&nbsp;
&nbsp; Daemon.forceCall = function (oDmn) {
&nbsp;
&nbsp;&nbsp;&nbsp; oDmn.INDEX += oDmn.BACKW ? -1 : 1;
&nbsp;
&nbsp;&nbsp;&nbsp; var
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bBreak = oDmn.task.call(oDmn.owner, oDmn.INDEX, oDmn.length, oDmn.BACKW) === false,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bEnd = oDmn.isAtEnd(), bInvert = oDmn.reversals &gt; 0;
&nbsp;
&nbsp;&nbsp;&nbsp; if (bEnd &amp;&amp; !bInvert || bBreak) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oDmn.pause();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;
&nbsp;&nbsp;&nbsp; }
&nbsp;
&nbsp;&nbsp;&nbsp; if (bEnd &amp;&amp; bInvert) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oDmn.BACKW = !oDmn.BACKW;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oDmn.reversals--;
&nbsp;&nbsp;&nbsp; }
&nbsp;
&nbsp;&nbsp;&nbsp; return true;
&nbsp;
&nbsp; };
&nbsp;
&nbsp;
/* SYSTEM NOT REQUIRED Daemon global object methods */
&nbsp;
&nbsp; /**
&nbsp; * Daemon global object optional methods (shortcurts). You could safely remove all or some of them,
&nbsp; * depending on your needs. If you want to remove them and are using the Daemon.safe subsystem you
&nbsp; * should remove also the Daemon.safe global object methods which require them.
&nbsp; **/
&nbsp;
&nbsp; Daemon.construct = function (aArgs) {
&nbsp;&nbsp;&nbsp; var oDmn = new this.blank();
&nbsp;&nbsp;&nbsp; this.apply(oDmn, aArgs);
&nbsp;&nbsp;&nbsp; return oDmn;
&nbsp; };
&nbsp;
&nbsp; Daemon.buildAround = function (oCtx, nRate, nLen) {
&nbsp;&nbsp;&nbsp; if (!oCtx.perform) { throw new TypeError("You can not create a daemon around an object devoid of a \"perform\" function"); }
&nbsp;&nbsp;&nbsp; return new this(oCtx, oCtx.perform, nRate || null, nLen || null, oCtx.create || null, oCtx.prepare || null);
&nbsp; };
&nbsp;
&nbsp;&nbsp;&nbsp; /* Warning! Calling Daemon.incorporate(@func) will modify the @func.prototype property! */
&nbsp;
&nbsp; Daemon.incorporate = function (fConstr) {
&nbsp;&nbsp;&nbsp; var oLegacy = fConstr.prototype;
&nbsp;&nbsp;&nbsp; fConstr.prototype = new Daemon.blank();
&nbsp;&nbsp;&nbsp; fConstr.prototype.legacy = oLegacy;
&nbsp;&nbsp;&nbsp; return fConstr;
&nbsp; };
&nbsp;
&nbsp;
/* SYSTEM REQUIRED Daemon instances methods */
&nbsp;
&nbsp; Daemon.prototype.isAtEnd = function () {
&nbsp;&nbsp;&nbsp; return this.BACKW ? isFinite(this.length) &amp;&amp; this.INDEX &lt; 1 : this.INDEX + 1 &gt; this.length;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.synchronize = function () {
&nbsp;&nbsp;&nbsp; if (this.PAUSED) { return; }
&nbsp;&nbsp;&nbsp; clearInterval(this.SESSION);
&nbsp;&nbsp;&nbsp; this.SESSION = setInterval(Daemon.forceCall, this.rate, this);
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.pause = function () {
&nbsp;&nbsp;&nbsp; clearInterval(this.SESSION);
&nbsp;&nbsp;&nbsp; this.PAUSED = true;
&nbsp; };
&nbsp;
&nbsp;
/* SYSTEM NOT REQUIRED Daemon instances methods */
&nbsp;
&nbsp; /**
&nbsp; * Basical user interface. You could remove this method, but your daemon will be virtually unusable.
&nbsp; * All other optional instances methods depend on this one or on the previous ones.
&nbsp; **/
&nbsp;
&nbsp; Daemon.prototype.start = function (bReverse) {
&nbsp;&nbsp;&nbsp; var bBackw = Boolean(bReverse);
&nbsp;&nbsp;&nbsp; if (this.BACKW === bBackw &amp;&amp; (this.isAtEnd() || !this.PAUSED)) { return false; }
&nbsp;&nbsp;&nbsp; this.BACKW = bBackw;
&nbsp;&nbsp;&nbsp; this.PAUSED = false;
&nbsp;&nbsp;&nbsp; if (this.onstart) { this.onstart.call(this.owner, this.INDEX, this.length, this.BACKW); }
&nbsp;&nbsp;&nbsp; this.synchronize();
&nbsp;&nbsp;&nbsp; return true;
&nbsp; };

&nbsp; Daemon.prototype.stop = function () {
&nbsp;&nbsp;&nbsp; this.pause();
&nbsp;&nbsp;&nbsp; if (this.onstop) { this.onstop.call(this.owner, this.INDEX, this.length, this.BACKW); }
&nbsp;&nbsp;&nbsp; delete this.INDEX;
&nbsp;&nbsp;&nbsp; delete this.BACKW;
&nbsp;&nbsp;&nbsp; delete this.reversals;
&nbsp; };
&nbsp;
&nbsp;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*******************************
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp; DAEMON IS NOW READY!&nbsp;&nbsp;&nbsp;&nbsp; *
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *******************************/
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*******************************
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POLYFILLS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *******************************/
&nbsp;
&nbsp;
&nbsp;
&nbsp;/*\
&nbsp;|*|
&nbsp;|*|&nbsp; IE-specific polyfill which enables the passage of arbitrary arguments to the
&nbsp;|*|&nbsp; callback functions of JavaScript timers (HTML5 standard syntax).
&nbsp;|*|
&nbsp;|*|&nbsp; https://developer.mozilla.org/en-US/docs/DOM/window.setInterval
&nbsp;|*|
&nbsp;|*|&nbsp; Syntax:
&nbsp;|*|&nbsp; var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
&nbsp;|*|&nbsp; var timeoutID = window.setTimeout(code, delay);
&nbsp;|*|&nbsp; var intervalID = window.setInterval(func, delay[, param1, param2, ...]);
&nbsp;|*|&nbsp; var intervalID = window.setInterval(code, delay);
&nbsp;|*|
&nbsp;\*/

/*
&nbsp; if (document.all &amp;&amp; !window.setTimeout.isPolyfill) {
&nbsp;&nbsp;&nbsp; var __nativeST__ = window.setTimeout;
&nbsp;&nbsp;&nbsp; window.setTimeout = function (vCallback, nDelay) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var aArgs = Array.prototype.slice.call(arguments, 2);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return __nativeST__(vCallback instanceof Function ? function () {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vCallback.apply(null, aArgs);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } : vCallback, nDelay);
&nbsp;&nbsp;&nbsp; };
&nbsp;&nbsp;&nbsp; window.setTimeout.isPolyfill = true;
&nbsp; }
&nbsp;&nbsp; &nbsp;
&nbsp; if (document.all &amp;&amp; !window.setInterval.isPolyfill) {
&nbsp;&nbsp;&nbsp; var __nativeSI__ = window.setInterval;
&nbsp;&nbsp;&nbsp; window.setInterval = function (vCallback, nDelay) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var aArgs = Array.prototype.slice.call(arguments, 2);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return __nativeSI__(vCallback instanceof Function ? function () {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vCallback.apply(null, aArgs);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } : vCallback, nDelay);
&nbsp;&nbsp;&nbsp; };
&nbsp;&nbsp;&nbsp; window.setInterval.isPolyfill = true;
&nbsp; }
*/</pre>
</div>
<h3 id="daemon-safe.js">daemon-safe.js</h3>
<p>What follows is the module which extends the <code>Daemon</code> constructor with a <code>Daemon.safe</code> sub-system. This library requires <strong>fork.js</strong> to work. <strong>The <code>Daemon.safe</code> constructor is as a dependent-clone of <code>Daemon</code> which uses a recursive invocation of the <code>setTimeout</code> timer rather than a single invocation of <code>setInterval</code>.</strong></p>
<div style="height: 400px; margin-bottom: 12px; overflow: auto;">
  <pre class="brush: js">
&nbsp;/*\
&nbsp;|*|
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *******************************
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; daemon-safe.js&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *******************************
&nbsp;|*|
&nbsp;|*|&nbsp; ver. 1.0 rev. 1
&nbsp;|*|
&nbsp;|*|&nbsp; fork.js - A JAVASCRIPT HIGLY SCALABLE DAEMONS MANAGER
&nbsp;|*|
&nbsp;|*|&nbsp; https://developer.mozilla.org/en-US/docs/JavaScript/Timers/Daemons
&nbsp;|*|&nbsp; https://developer.mozilla.org/User:fusionchess
&nbsp;|*|
&nbsp;|*|&nbsp; This framework is released under the GNU Public License, version 3 or later.
&nbsp;|*|&nbsp; http://www.gnu.org/licenses/gpl-3.0-standalone.html
&nbsp;|*|
&nbsp;\*/
&nbsp;
"use strict";
&nbsp;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**************************************
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp; THE SAFE-DAEMON SUB-SYSTEM&nbsp;&nbsp;&nbsp;&nbsp; *
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **************************************/
&nbsp;
&nbsp;
&nbsp;
/* The "Daemon.safe" constructor */
&nbsp;
&nbsp; Daemon.safe = function () { Daemon.apply(this, arguments); };
&nbsp;
&nbsp;&nbsp;&nbsp; /* Create the Daemon.safe.blank() constructor and the Daemon.safe.context object */
&nbsp;
&nbsp; Daemon.safe.blank = function () {};
&nbsp; Daemon.safe.context = Daemon.safe.prototype;
&nbsp; Daemon.TO_BE_DEFINED = Daemon.safe.blank.prototype; /* Make love with the GC :-) */
&nbsp; Daemon.safe.blank.prototype = /* Important! */ Daemon.safe.prototype = /* Important! */ new Daemon.blank();
&nbsp; Daemon.safe.prototype.constructor = Daemon.safe;
&nbsp; Daemon.TO_BE_DEFINED.constructor = Daemon.safe.context.constructor = Object;
&nbsp;
&nbsp;
/* SYSTEM REQUIRED Daemon.safe global object methods */
&nbsp;
&nbsp; Daemon.safe.forceCall = function (oDmn) {
&nbsp;
&nbsp;&nbsp;&nbsp; oDmn.INDEX += oDmn.BACKW ? -1 : 1;
&nbsp;
&nbsp;&nbsp;&nbsp; var
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bBreak = oDmn.task.call(oDmn.owner, oDmn.INDEX, oDmn.length, oDmn.BACKW) === false,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bEnd = oDmn.isAtEnd(), bInvert = oDmn.reversals &gt; 0;
&nbsp;
&nbsp;&nbsp;&nbsp; if (bEnd &amp;&amp; !bInvert || bBreak) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oDmn.PAUSED = true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;
&nbsp;&nbsp;&nbsp; }
&nbsp;
&nbsp;&nbsp;&nbsp; if (bEnd &amp;&amp; bInvert) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oDmn.BACKW = !oDmn.BACKW;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oDmn.reversals--;
&nbsp;&nbsp;&nbsp; }
&nbsp;
&nbsp;&nbsp;&nbsp; oDmn.synchronize();
&nbsp;
&nbsp;&nbsp;&nbsp; return true;
&nbsp;
&nbsp; };
&nbsp;
&nbsp;
/* SYSTEM NOT REQUIRED Daemon.safe global object methods */
&nbsp;
&nbsp; /**
&nbsp; * Daemon.safe global object optional methods (shortcurts). You could safely remove all or some of
&nbsp; * them, depending on your needs.
&nbsp; **/
&nbsp;
&nbsp;&nbsp;&nbsp; /* Warnign: this method requires the global Daemon.construct() method */
&nbsp; Daemon.safe.construct = Daemon.construct;
&nbsp;
&nbsp;&nbsp;&nbsp; /* Warnign: this method requires the global Daemon.buildAround() method */
&nbsp; Daemon.safe.buildAround = Daemon.buildAround;
&nbsp;
&nbsp;&nbsp;&nbsp; /* Warnign: this method requires the global Daemon.incorporate() method */
&nbsp; Daemon.safe.incorporate = Daemon.incorporate;
&nbsp;
&nbsp;
/* SYSTEM REQUIRED Daemon.safe instances methods */
&nbsp;
&nbsp; Daemon.safe.prototype.synchronize = function () {
&nbsp;&nbsp;&nbsp; if (this.PAUSED) { return; }
&nbsp;&nbsp;&nbsp; clearTimeout(this.SESSION);
&nbsp;&nbsp;&nbsp; this.SESSION = setTimeout(Daemon.safe.forceCall, this.rate, this);
&nbsp; };

&nbsp; Daemon.safe.prototype.pause = function () {
&nbsp;&nbsp;&nbsp; clearTimeout(this.SESSION);
&nbsp;&nbsp;&nbsp; this.PAUSED = true;
&nbsp; };

&nbsp;
/* SYSTEM NOT REQUIRED Daemon.safe instances methods */

&nbsp; /* [inherited from Daemon.prototype] */


&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*****************************************
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp; THE SAFE-DAEMON IS NOW READY!&nbsp;&nbsp;&nbsp;&nbsp; *
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *****************************************/</pre>
</div>
<h3 id="daemons-methods.js">daemons-methods.js</h3>
<p>What follows is a module which collects a wide and scalable list of additional methods for instances of <code>Daemon</code> (and <code>Daemon.safe</code>). This module requires <strong>fork.js</strong> to work.&nbsp; <strong>You can safely remove all or some of these methods, depending on your needs (modularity).</strong>&nbsp; When a method requires the presence of another method (it is relatively rare) there is a comment which explains why. If there are not comments to that method it depends only on the base system.</p>
<div style="height: 400px; margin-bottom: 12px; overflow: auto;">
  <pre class="brush: js">
 /*\
&nbsp;|*|
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *******************************
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; daemon-methods.js&nbsp;&nbsp;&nbsp;&nbsp; *
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *******************************
&nbsp;|*|
&nbsp;|*|&nbsp; ver. 1.0 rev. 1
&nbsp;|*|
&nbsp;|*|&nbsp; fork.js - A JAVASCRIPT HIGLY SCALABLE DAEMONS MANAGER
&nbsp;|*|
&nbsp;|*|&nbsp; https://developer.mozilla.org/en-US/docs/JavaScript/Timers/Daemons
&nbsp;|*|&nbsp; https://developer.mozilla.org/User:fusionchess
&nbsp;|*|
&nbsp;|*|&nbsp; This framework is released under the GNU Public License, version 3 or later.
&nbsp;|*|&nbsp; http://www.gnu.org/licenses/gpl-3.0-standalone.html
&nbsp;|*|
&nbsp;\*/
&nbsp;
"use strict";
&nbsp;
&nbsp;
/* SYSTEM NOT REQUIRED Daemon instances methods */
&nbsp;
&nbsp;&nbsp;&nbsp; /* Movement */
&nbsp;
&nbsp; Daemon.prototype.syncStart = function (bReverse) {
&nbsp;&nbsp;&nbsp; this.synchronize();
&nbsp;&nbsp;&nbsp; if (this.start(bReverse || false)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Daemon.forceCall(this);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; return false;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.play = function (bSync) {
&nbsp;&nbsp;&nbsp; /* Warnign: this method OPTIONALLY requires the Daemon.prototype.syncStart() method */
&nbsp;&nbsp;&nbsp; return this[bSync ? "start" : "syncStart"]();
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.reversePlay = function (bSync) {
&nbsp;&nbsp;&nbsp; /* Warnign: this method OPTIONALLY requires the Daemon.prototype.syncStart() method */
&nbsp;&nbsp;&nbsp; return this[bSync ? "start" : "syncStart"](true);
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.move = function (bSync, nCycles, bDirection) {
&nbsp;&nbsp;&nbsp; /* Warnign: this method OPTIONALLY requires the Daemon.prototype.syncStart() method */
&nbsp;&nbsp;&nbsp; if (arguments.length &gt; 1 &amp;&amp; !isNaN(nCycles)) { this.reversals = Number(nCycles); }
&nbsp;&nbsp;&nbsp; this[bSync ? "start" : "syncStart"](arguments.length &gt; 2 ? bDirection : this.isAtEnd() !== this.BACKW);
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.turn = function (bSync) {
&nbsp;&nbsp;&nbsp; /* Warnign: this method OPTIONALLY requires the Daemon.prototype.syncStart() method */
&nbsp;&nbsp;&nbsp; this[bSync ? "start" : "syncStart"](!this.BACKW);
&nbsp; };
&nbsp;
&nbsp;&nbsp;&nbsp; /* Settings tools */
&nbsp;
&nbsp; Daemon.prototype.makeLoop = function () {
&nbsp;&nbsp;&nbsp; this.reversals = Infinity;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.unmakeLoop = function () {
&nbsp;&nbsp;&nbsp; this.reversals = 0;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.setRate = function (vTo) {
&nbsp;&nbsp;&nbsp; var nRate = Number(vTo);
&nbsp;&nbsp;&nbsp; if (!isFinite(nRate) || nRate &lt; 1) { return; }
&nbsp;&nbsp;&nbsp; this.rate = nRate;
&nbsp;&nbsp;&nbsp; this.synchronize();
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.forcePosition = function (vTo) {
&nbsp;&nbsp;&nbsp; if (isFinite(vTo)) { this.INDEX = Math.round(Math.abs(vTo)); }
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.getDuration = function () {
&nbsp;&nbsp;&nbsp; return this.rate * this.length;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.getDirection = function () {
&nbsp;&nbsp;&nbsp; return this.isAtEnd() !== this.BACKW;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.getPosition = function () {
&nbsp;&nbsp;&nbsp; return this.INDEX;
&nbsp; };
&nbsp;
&nbsp;&nbsp;&nbsp; /* Instantaneous movement (synchronous). */
&nbsp;
&nbsp; Daemon.prototype.makeSteps = function (nHowMany, bReverse, bForce) {
&nbsp;&nbsp;&nbsp; if (nHowMany === 0) { return true; }
&nbsp;&nbsp;&nbsp; if (isNaN(nHowMany)) { return false; }
&nbsp;&nbsp;&nbsp; var nIdx = 0, nLen = Math.round(Math.abs(nHowMany)), bContinue = true, bBackw = nHowMany &gt; 0 === Boolean(bReverse);
&nbsp;&nbsp;&nbsp; this.BACKW = bBackw;
&nbsp;&nbsp;&nbsp; for (nIdx; nIdx &lt; nLen &amp;&amp; bContinue; nIdx++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (this.BACKW === bBackw &amp;&amp; this.isAtEnd()) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (this.reversals &gt; 0) { this.BACKW = bBackw = !this.BACKW; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else { break; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bContinue = Daemon.forceCall(this) || bForce;
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; return nIdx === nLen;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.skipTo = function (nIdx, bForce) {
&nbsp;&nbsp;&nbsp; /* Warnign: this method requires the Daemon.prototype.makeSteps() method */
&nbsp;&nbsp;&nbsp; if (nIdx === this.INDEX) { return; }
&nbsp;&nbsp;&nbsp; if (isFinite(this.length) &amp;&amp; nIdx &lt; 0 || nIdx &gt; this.length) { return; }
&nbsp;
&nbsp;&nbsp;&nbsp; var
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bDirection = (this.INDEX !== 0 &amp;&amp; this.INDEX !== this.length) === this.BACKW,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bSuccess = this.makeSteps(this.INDEX - nIdx, true, bForce);
&nbsp;
&nbsp;&nbsp;&nbsp; if (this.INDEX !== 0 &amp;&amp; this.INDEX !== this.length) { this.BACKW = bDirection; }
&nbsp;&nbsp;&nbsp; return bSuccess;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.skipFor = function (nDelta, bForce) {
&nbsp;&nbsp;&nbsp; /* Warnign: this method requires the Daemon.prototype.makeSteps() method */
&nbsp;&nbsp;&nbsp; return this.makeSteps(nDelta, this.isAtEnd() !== this.BACKW, bForce);
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.close = function (bReverse, bForce) {
&nbsp;&nbsp;&nbsp; /* Warnign: this method requires the Daemon.prototype.makeSteps() method */
&nbsp;&nbsp;&nbsp; if (!isFinite(this.length)) { return false; }
&nbsp;&nbsp;&nbsp; this.pause();
&nbsp;&nbsp;&nbsp; this.reversals = 0;
&nbsp;&nbsp;&nbsp; return this.makeSteps(bReverse ? this.INDEX : this.length - this.INDEX, bReverse, bForce);
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.reclose = function (bForce) {
&nbsp;&nbsp;&nbsp; /* Warnign: this method requires the Daemon.prototype.makeSteps() and Daemon.prototype.close() methods */
&nbsp;&nbsp;&nbsp; return this.close(this.isAtEnd() !== this.BACKW, bForce || false);
&nbsp; };
&nbsp;
&nbsp; /* Others */
&nbsp;
&nbsp; Daemon.prototype.restart = function () {
&nbsp;&nbsp;&nbsp; this.stop();
&nbsp;&nbsp;&nbsp; this.start();
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.loopUntil = function (vDate) {
&nbsp;&nbsp;&nbsp; if (!isFinite(this.length)) { return; }
&nbsp;&nbsp;&nbsp; var nTime = vDate.constructor === Date ? vDate.getTime() : isNaN(vDate) ? Date.parse(vDate) : vDate;
&nbsp;&nbsp;&nbsp; if (isFinite(nTime) &amp;&amp; nTime &gt; Date.now()) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.reversals = Math.floor((nTime - Date.now() - (this.BACKW ? this.INDEX : this.length - this.INDEX) * this.rate) / (this.length * this.rate));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.start(this.isAtEnd() !== this.BACKW);
&nbsp;&nbsp;&nbsp; }
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.spread = function (nTime) {
&nbsp;&nbsp;&nbsp; if (!isFinite(this.length)) { throw new TypeError("Daemon.prototype.spread - the length is not a finite number. Use Daemon.prototype.adaptLength()."); }
&nbsp;&nbsp;&nbsp; if (nTime &gt; 0) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.rate = Math.floor(nTime / this.length);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.synchronize();
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; return this.rate;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.adaptLength = function (nTime) {
&nbsp;&nbsp;&nbsp; this.length = Math.floor(nTime / this.rate);
&nbsp;&nbsp;&nbsp; return this.length;
&nbsp; };
&nbsp;
&nbsp; Daemon.prototype.playUntil = function (vDate) {
&nbsp;&nbsp;&nbsp; var nTime = vDate.constructor === Date ? vDate.getTime() : isNaN(vDate) ? Date.parse(vDate) : vDate;
&nbsp;&nbsp;&nbsp; if (isFinite(nTime) &amp;&amp; nTime &gt; Date.now()) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.length = Math.floor((nTime - Date.now()) / this.rate) + this.INDEX;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.pause();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.start();
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; return this.length;
&nbsp; };</pre>
</div>
<h2 id="Manual">Manual</h2>
<h3 id="The_constructor">The constructor</h3>
<h4 id="Syntax">Syntax</h4>
<pre class="syntaxbox">
var myDaemon = new Daemon(<em>thisObject</em>, <em>callback</em>[, <em>rate</em>[, <em>length</em>[, <em>init</em>[, <em>onstart</em>]]]]);</pre>
<h4 id="Description">Description</h4>
<p>Constructs a JavaScript Object containing all informations needed by an animation (like the <a href="/en-US/docs/JavaScript/Reference/Operators/this" title="en-US/docs/JavaScript/Reference/Operators/this"><code>this</code></a> object, the callback function, the length, the frame-rate, the number of cycles, the <code>init</code> and the <code>onstart</code> functions).</p>
<h4 id="Arguments">Arguments</h4>
<dl>
  <dt>
    <code>thisObject</code></dt>
  <dd>
    The <a href="/en-US/docs/JavaScript/Reference/Operators/this" title="en-US/docs/JavaScript/Reference/Operators/this"><code>this</code></a> object on which will be called the callback function. It can be an <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object">object</a> or <code>null</code>. If is <code>null</code>, the <code>this</code> object will point to the global <code>Deamon.context</code> object (see below).</dd>
  <dt>
    <code>callback</code></dt>
  <dd>
    The function which will be invoked repeatedly. It will be called with three parameters: <code><em>index</em></code> (the iterative index of each invocation), <code><em>length</em></code> (the <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> of total invocations assigned to the daemon - finite or <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>) and <code><em>backwards</em></code> (a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean" title="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean">boolean</a> expressing whether the process is going backwards or not). It will be something like <code><em>callback</em>.call(<em>thisObject</em>, <em>index</em>, <em>length</em>, <em>backwards</em>)</code>. If the <code><em>callback</em></code> function returns a <code>false</code> value the daemon will be paused.</dd>
  <dt>
    <code>rate</code> [optional]</dt>
  <dd>
    The time lapse (in <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> of milliseconds) between each invocation. The default value is 100.</dd>
  <dt>
    <code>length</code> [optional]</dt>
  <dd>
    The total number of invocations. It can be a positive integer or <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>. The default value is <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>.</dd>
  <dt>
    <code>init</code> [optional]</dt>
  <dd>
    The <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function" title="/en-US/docs/JavaScript/Reference/Global_Objects/Function">function</a> which will be synchronously invoked once during the creation of the daemon and then assigned to the <code>onstop</code> property. It will be called with the same three arguments of the <code>callback</code> function. They will also have the same values of the last invocation of the <code>callback</code> function.</dd>
  <dt>
    <code>onstart</code> [optional]</dt>
  <dd>
    The <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function" title="/en-US/docs/JavaScript/Reference/Global_Objects/Function">function</a> which will be synchronously invoked on whenever the <code>start</code> event occurs. It will be assigned to the <code>onstart</code> property. It will be called with three arguments: <code><em>index</em></code> (the iterative index of each invocation), <code><em>length</em></code> (the <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> of total invocations assigned to the daemon - finite or <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>) and <code><em>backwards</em></code> (a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean" title="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean">boolean</a> expressing whether the process is going backwards or not).</dd>
</dl>
<h3 id="Daemon_global_object_properties">Daemon global object properties</h3>
<dl>
  <dt>
    <code>Daemon.context</code></dt>
  <dd>
    An empty <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object">object</a> used as default&nbsp;<a href="/en-US/docs/JavaScript/Reference/Operators/this" title="en-US/docs/JavaScript/Reference/Operators/this"><code>this</code></a> object when the <code><em>thisObject</em></code> is not specified during the construction of the daemon. If you want your <code><em>callback</em></code> function to be invoked with a <code>null</code> <a href="/en-US/docs/JavaScript/Reference/Operators/this" title="en-US/docs/JavaScript/Reference/Operators/this"><code>this</code></a> object you have to manually set the <code>owner</code> property to <code>null</code>.</dd>
</dl>
<h3 id="Daemon_global_object_methods">Daemon global object methods</h3>
<dl>
  <dt>
    <code>Daemon.forceCall(<em>daemonInstance</em>)</code></dt>
  <dd>
    Forces a callback to the <code><em>daemonInstance</em>.task</code> function regardless of the fact that the end has been reached or not. In any case the internal <code>INDEX</code> property will be increased/decreased (depending on the actual direction of the daemon).</dd>
  <dt>
    <code>Daemon.construct(<em>arrayOfArguments</em>)</code></dt>
  <dd>
    Returns a new daemon constructed upon an <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Array" title="/en-US/docs/JavaScript/Reference/Global_Objects/Array">array</a> of arguments. It is very similar to the <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply" title="/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply"><code>Function.prototype.apply()</code></a> method.</dd>
  <dt>
    <code>Daemon.buildAround(<em>context</em>[, <em>rate</em>[, <em>length</em>]])</code></dt>
  <dd>
    Returns a new daemon built around a <code><em>context</em></code> object. The <code><em>context</em></code> object must cointain *at least* a <code>perform</code> property pointing to what you want to be the <code><em>callback</em></code> function of the daemon. It can also optionally contain a <code>create</code> and a <code>prepare</code> properties pointing respectively to the two functions you want to be the <code><em>init</em></code> and <code><em>onstart</em></code> functions of <code>Daemon</code> constructor's arguments. The <code><em>context</em></code> object will be also the <a href="/en-US/docs/JavaScript/Reference/Operators/this" title="en-US/docs/JavaScript/Reference/Operators/this"><code>this</code></a> object of your <code>callback</code> function. So you can populate it with all your custom properties. and methods. The only required one property is <code>perform</code>.
    <h5 id="Sample_usage.3A">Sample usage:</h5>
    <pre class="syntaxbox">
var myDaemon = Daemon.buildAround({
	"create": function () { [custom code] },  // optional
	"prepare": function () { [custom code] },  // optional
	"perform": function () { [custom code] },  // required
	"customProperty": [custom value],
	"myCustomMethod": function () { [custom code] },
	"anotherCustomProperty": [custom value],
	"etc.": "etc."
}, 200, 30);
</pre>
  </dd>
  <dt>
    <code>Daemon.incorporate(<em>function</em>)</code></dt>
  <dd>
    The <code><em>function</em>.prototype</code> property will replaced with a <code>new Daemon()</code> object. The old replaced prototype will be preserved within a new property of the new <code><em>function</em>.prototype</code> object named <code>legacy</code>.</dd>
</dl>
<h3 id="Other_constructors">Other constructors</h3>
<dl>
  <dt>
    <code>Daemon.blank()</code></dt>
  <dd>
    Constructs a new instance of <code>Daemon</code> without own properties. This constructor is useful in order to create your own *MySomeDaemon* constructors through the <code>MySomeDaemon.prototype = new Daemon.blank();</code> assignment.</dd>
  <dt>
    <code>Daemon.safe()</code> [optional module daemon-safe.js]</dt>
  <dd>
    <h5 id="Syntax">Syntax</h5>
    <pre class="syntaxbox">
var myDaemon = new Daemon.safe(<em>thisObject</em>, <em>callback</em>[, <em>rate</em>[, <em>length</em>[, <em>init</em>[, <em>onstart</em>]]]]);</pre>
    <h5 id="Description">Description</h5>
    <p><code>Daemon.safe</code> is a clone of the Daemon constructor based on recursive invocations of <a href="/en-US/docs/DOM/window.setTimeout" title="/en-US/docs/DOM/window.setTimeout"><code>setTimeout</code></a> rather than on a single invocation of <a href="/en-US/docs/DOM/window.setInterval" title="/en-US/docs/DOM/window.setInterval"><code>setInterval</code></a>. See the <strong>daemon-safe.js</strong> module for details.</p>
    <div class="note">
      <strong>Note:</strong> The <code>Daemon.safe</code> constructor is not part of the base system.</div>
  </dd>
  <dt>
    <code>Daemon.safe.blank()</code> [optional module daemon-safe.js]</dt>
  <dd>
    <p>The same as for <code>Daemon.blank</code>, but applied to the <code>Daemon.safe</code> constructor.</p>
    <div class="note">
      <strong>Note:</strong> The <code>Daemon.safe</code> constructor is not part of the base system.</div>
  </dd>
</dl>
<h3 id="Daemon_instances_properties">Daemon instances properties</h3>
<dl>
  <dt>
    <code>myDaemon.owner</code></dt>
  <dd>
    The <a href="/en-US/docs/JavaScript/Reference/Operators/this" title="en-US/docs/JavaScript/Reference/Operators/this"><code>this</code></a> object on which is executed the daemon (read/write). It can be an <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object">object</a> or <code>null</code>. Its default value is <code>Daemon.context</code>.</dd>
  <dt>
    <code>myDaemon.task</code></dt>
  <dd>
    The function which will be repeatedly invoked (read/write). It will be called with three arguments: <code><em>index</em></code> (the iterative index of each invocation), <code><em>length</em></code> (the <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> of total invocations assigned to the daemon - finite or <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>) and <code><em>backwards</em></code> (a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean" title="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean">boolean</a> expressing whether the process is going backwards or not). See above. If the myDaemon.task function returns a <code>false</code> value the daemon will be paused.</dd>
  <dt>
    <code>myDaemon.rate</code></dt>
  <dd>
    The time lapse (in number of milliseconds) between each invocation (read/write).</dd>
  <dt>
    <code>myDaemon.length</code></dt>
  <dd>
    The total <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> of invocations. It can be a positive integer or <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code> (read/write).</dd>
  <dt>
    <code>myDaemon.reversals</code></dt>
  <dd>
    The <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> of times the daemon must be restarted (read/write). Set it to <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code> for a “loop mode”.</dd>
  <dt>
    <code>myDaemon.onstart</code></dt>
  <dd>
    The <code>start</code> listener (read/write). It will be called with three arguments: <code><em>index</em></code> (the iterative index of each invocation), <code><em>length</em></code> (the <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> of total invocations assigned to the daemon - finite or <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>) and <code><em>backwards</em></code> (a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean" title="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean">boolean</a> expressing whether the process is going backwards or not).</dd>
  <dt>
    <code>myDaemon.onstop</code></dt>
  <dd>
    <p>The <code>stop</code> listener (read/write). It will be called with three arguments: <code><em>index</em></code> (the iterative index of each invocation), <code><em>length</em></code> (the <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> of total invocations assigned to the daemon - finite or <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>) and <code><em>backwards</em></code> (a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean" title="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean">boolean</a> expressing whether the process is going backwards or not).</p>
    <div class="note">
      <strong>Note:</strong> The <code>stop()</code> method is not part of the base system.</div>
  </dd>
</dl>
<h3 id="Daemon_instances_methods">Daemon instances methods</h3>
<dl>
  <dt>
    <code>myDaemon.isAtEnd()</code></dt>
  <dd>
    Returns a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean" title="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean">boolean</a> expressing whether the daemon is at the start/end position or not.</dd>
  <dt>
    <code>myDaemon.synchronize()</code></dt>
  <dd>
    Synchronize the timer of a started daemon with the time of invocation of <code>myDaemon.synchronize()</code>. If the <code>rate</code> property has been changed the daemon will be updated with the new <code>rate</code> value.</dd>
  <dt>
    <code>myDaemon.pause()</code></dt>
  <dd>
    Pauses the daemon.</dd>
  <dt>
    <code>myDaemon.start([<em>backwards</em>])</code></dt>
  <dd>
    Starts the daemon forward (index of each invocation increasing) or backwards (index decreasing).</dd>
  <dt>
    <code>myDaemon.stop()</code></dt>
  <dd>
    Stops the daemon. All original properties will be restored. If it exists a <code>stop</code> listener it will be called with three arguments: <code><em>index</em></code> (the iterative index of each invocation), <code><em>length</em></code> (the <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> of total invocations assigned to the daemon - finite or <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>) and <code><em>backwards</em></code> (a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean" title="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean">boolean</a> expressing whether the process is going backwards or not).</dd>
</dl>
<h3 id="Additional_instances_methods_.5Boptional_module_daemons-methods.js.5D">Additional instances methods [optional module daemons-methods.js]</h3>
<dl>
  <dt>
    <code>myDaemon.syncStart([<em>backwards</em>])</code></dt>
  <dd>
    Starts the daemon with the first callback synchronous.</dd>
  <dt>
    <code>myDaemon.play([<em>synchronous</em>])</code></dt>
  <dd>
    Starts the daemon forward. If the daemon was running in the same direction nothing will happen. If the argument is <code>true</code> the first callback will be synchronous.</dd>
  <dt>
    <code>myDaemon.reversePlay([<em>synchronous</em>])</code></dt>
  <dd>
    Starts the daemon backwards. If the daemon was running in the same direction nothing will happen. If the argument is <code>true</code> the first callback will be synchronous.</dd>
  <dt>
    <code>myDaemon.move([<em>synchronous</em>[, <em>reversals</em>[, <em>backwards</em>]]])</code></dt>
  <dd>
    Starts a daemon synchronously or not. If the <code><em>reversals</em></code> argument is specified the <code>myDaemon.reversals</code> property will be setted on it. If the <code><em>backwards</em></code> argument is specified the daemon will move forward (<code>false</code>) or backwards (<em>true</em>). If it is not specified the daemon will start in the same direction in which it has been left. If the daemon was running in the same direction, only the <code>reversals</code> property will be possibly updated.</dd>
  <dt>
    <code>myDaemon.turn()</code></dt>
  <dd>
    Inverts the direction of the daemon. The <code>reversals</code> property will not be decreased.</dd>
  <dt>
    <code>myDaemon.makeLoop()</code></dt>
  <dd>
    Sets the <code>reversals</code> property equal to <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>.</dd>
  <dt>
    <code>myDaemon.unmakeLoop()</code></dt>
  <dd>
    Sets the <code>reversals</code> property equal to 0.</dd>
  <dt>
    <code>myDaemon.setRate(<em>milliseconds</em>)</code></dt>
  <dd>
    Sets the time lapse between calls (in milliseconds). If the daemon is running it will be immediately updated with the new property.</dd>
  <dt>
    <code>myDaemon.forcePosition(<em>index</em>)</code></dt>
  <dd>
    Sets the internal <code>INDEX</code> property equal to the <code><em>index</em></code> argument without any kind of control about the range.</dd>
  <dt>
    <code>myDaemon.getDuration()</code></dt>
  <dd>
    Returns the duration of the daemon in milliseconds.</dd>
  <dt>
    <code>myDaemon.getPosition()</code></dt>
  <dd>
    Returns the internal <code>INDEX</code> property.</dd>
  <dt>
    <code>myDaemon.makeSteps(<em>howMany</em>[, <em>backwards</em>[, <em>force</em>]])</code></dt>
  <dd>
    Calls synchronously the <code><em>callback</em></code> function <code><em>howMany</em></code> times. Forwards or backwards. If the <code><em>force</em></code> argument is setted to true the possible <code>return false</code> of the <code><em>callback</em></code> function will be ignored.</dd>
  <dt>
    <code>myDaemon.skipTo(<em>index</em>[, <em>force</em>])</code></dt>
  <dd>
    Calls synchronously the <code><em>callback</em></code> function the number of times needed to reach the <code><em>index</em></code> position. If the <code><em>force</em></code> argument is setted to true the possible <code>return false</code> of the <code><em>callback</em></code> function will be ignored.</dd>
  <dt>
    <code>myDaemon.skipFor(<em>delta</em>[, <em>force</em>])</code></dt>
  <dd>
    Calls synchronously the <code><em>callback</em></code> function <code><em>howMany</em></code> times in the same direction in which it was oriented. If the <code><em>force</em></code> argument is setted to true the possible <code>return false</code> of the <code><em>callback</em></code> function will be ignored.</dd>
  <dt>
    <code>myDaemon.close([<em>backwards</em>, <em>force</em>])</code></dt>
  <dd>
    Closes the daemon, doing <strong>synchronously</strong> all pending operations forward (index of each invocation increasing) or backwards (index decreasing). If the <code><em>force</em></code> argument is setted to true the possible <code>return false</code> of the <code><em>callback</em></code> function will be ignored.</dd>
  <dt>
    <code>myDaemon.reclose([<em>force</em>])</code></dt>
  <dd>
    Closes the daemon, doing <strong>synchronously</strong> all pending operations in the same direction in which is oriented the daemon. If the <code><em>force</em></code> argument is setted to true the possible <code>return false</code> of the <code><em>callback</em></code> function will be ignored.</dd>
  <dt>
    <code>myDaemon.restart()</code></dt>
  <dd>
    Stops and restarts the daemon.</dd>
  <dt>
    <code>myDaemon.loopUntil(<em>date</em>)</code></dt>
  <dd>
    Sets the reversals property in function of a future <code><em>date</em></code>. The <code><em>date</em></code> argument can be a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Date" title="/en-US/docs/JavaScript/Reference/Global_Objects/Date"><code>Date</code></a> object, a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/String" title="/en-US/docs/JavaScript/Reference/Global_Objects/String">string</a> expressing the date in GMTString format, or a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> expressing the number of milliseconds since January 1, 1970, 00:00:00 UTC.</dd>
  <dt>
    <code>myDaemon.spread(<em>milliseconds</em>)</code></dt>
  <dd>
    Sets the the total duration of the daemon in milliseconds. Only the <code>rate</code> property will be modified.</dd>
  <dt>
    <code>myDaemon.adaptLength(<em>milliseconds</em>)</code></dt>
  <dd>
    Sets the internal <code>length</code> property equal to <code><em>milliseconds</em></code> / <code>myDaemon.rate</code>.</dd>
  <dt>
    <code>myDaemon.playUntil(<em>date</em>)</code></dt>
  <dd>
    Starts the daemon forward and sets the the total duration of it in function of a future <code><em>date</em></code>. The <code><em>date</em></code> argument can be a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Date" title="/en-US/docs/JavaScript/Reference/Global_Objects/Date"><code>Date</code></a> object, a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/String" title="/en-US/docs/JavaScript/Reference/Global_Objects/String">string</a> expressing the date in GMTString format, or a <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/JavaScript/Reference/Global_Objects/Number">number</a> expressing the number of milliseconds since January 1, 1970, 00:00:00 UTC. Only the length property will be modified.</dd>
</dl>
<h2 id="Examples">Examples</h2>
<h4 id="Example_.231.3A_A_standard_instantiation_.E2.80.93_new_Daemon()">Example #1: A standard instantiation – <code>new Daemon()</code></h4>
<div style="height: 400px; margin-bottom: 12px; overflow: auto;">
  <pre class="brush: html">
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
&lt;title&gt;new Daemon(&amp;hellip;)&lt;/title&gt;
&lt;script type="text/javascript" src="fork.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="daemons-methods.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
&nbsp;
function perform (nIndex, nLength, bBackw) {
&nbsp; // http://tyleregeto.com/text-animation-in-javascript
&nbsp; for (var oLetter, nLetter = 0; nLetter &lt; aLetters.length; nLetter++) {
&nbsp;&nbsp;&nbsp; oLetter = aLetters[nLetter];
&nbsp;&nbsp;&nbsp; var nDist = nMaxDist - nMaxDist * nIndex / nLength;
&nbsp;&nbsp;&nbsp; oLetter.pos += 0.08;
&nbsp;&nbsp;&nbsp; oLetter.elem.style.top = Math.sin(oLetter.pos) * nDist + "px";
&nbsp;&nbsp;&nbsp; oLetter.elem.style.left = Math.cos(oLetter.pos) * nDist * 5 + "px";
&nbsp; }
}
&nbsp;
function prepare () {
&nbsp; // build letters list
&nbsp; // http://tyleregeto.com/text-animation-in-javascript
&nbsp; this.textContent = "";
&nbsp; aLetters.length = 0; &nbsp;
&nbsp; for (var oSpan, oLetter, nLetter = 0, nLen = sText.length; nLetter &lt; nLen; nLetter++) {
&nbsp;&nbsp;&nbsp; oSpan = document.createElement("span");
&nbsp;&nbsp;&nbsp; oSpan.textContent = sText[nLetter];
&nbsp;&nbsp;&nbsp; oLetter = { "elem": oSpan, "parent": this };
&nbsp;&nbsp;&nbsp; aLetters.push(oLetter);
&nbsp;&nbsp;&nbsp; oLetter.pos = Math.random() * 50;
&nbsp;&nbsp;&nbsp; oLetter.elem.style.position = "relative";
&nbsp;&nbsp;&nbsp; this.appendChild(oSpan);
&nbsp; }
}
&nbsp;
var
&nbsp; nMaxDist = 25, aLetters = [], sText = "Do you feel lucky, punk?",
&nbsp; oRecompose = new Daemon(document.createElement("p"), perform, 33, 30, prepare);
&nbsp;
onload = function () {
&nbsp; oRecompose.owner.id = "perform-me";
&nbsp; document.body.appendChild(oRecompose.owner);
&nbsp; oRecompose.play();
};
&nbsp;
&lt;/script&gt;
&nbsp;
&lt;style type="text/css"&gt;
body {
&nbsp; font-family: monospace, sans-serif;
&nbsp; background: #DDDDDD;
&nbsp; overflow: hidden;
}
&nbsp;
#perform-me {
&nbsp; margin: 50px;
&nbsp; font-size: 20px;
&nbsp; line-height: 20px;
}
&lt;/style&gt;
&lt;/head&gt;
&nbsp;
&lt;body&gt;
&nbsp;
&lt;h1&gt;new Daemon(&lt;em&gt;@thisObject&lt;/em&gt;, &lt;em&gt;@callback&lt;/em&gt;[, &lt;em&gt;@rate&lt;/em&gt;, &lt;em&gt;@length&lt;/em&gt;, &lt;em&gt;@init&lt;/em&gt;, &lt;em&gt;@onstart&lt;/em&gt;])&lt;/h1&gt;
&nbsp;
&lt;p&gt;&lt;button onclick="oRecompose.skipTo(11);"&gt;skipTo(11)&lt;/button&gt;
&lt;button onclick="oRecompose.makeSteps(29);"&gt;makeSteps(29)&lt;/button&gt;
&lt;button onclick="oRecompose.fixPosition(-13);"&gt;fixPosition(-13)&lt;/button&gt;
&lt;button onclick="oRecompose.play();"&gt;play&lt;/button&gt;
&lt;button onclick="oRecompose.turn();"&gt;turn&lt;/button&gt;
&lt;button onclick="oRecompose.pause();"&gt;pause&lt;/button&gt;
&lt;button onclick="oRecompose.reversePlay();"&gt;reversePlay&lt;/button&gt;
&lt;button onclick="oRecompose.reversals = 2;alert('changed');"&gt;two reversals&lt;/button&gt;
&lt;button onclick="oRecompose.makeLoop();alert('changed');"&gt;makeLoop&lt;/button&gt;
&lt;button onclick="oRecompose.unmakeLoop();alert('changed');"&gt;unmakeLoop&lt;/button&gt;
&lt;button onclick="oRecompose.close();"&gt;close&lt;/button&gt;
&lt;button onclick="oRecompose.reclose();"&gt;reclose&lt;/button&gt;&lt;br /&gt;
frame rate: &lt;input type="text" id="vello" value="33" style="width: 40px;" onkeypress="return event.charCode===0||/\d/.test(String.fromCharCode(event.charCode));" onkeyup="if(isFinite(this.value)&amp;&amp;Number(this.value)&gt;0){oRecompose.setRate(this.value);}" /&gt;&lt;/p&gt;
&nbsp;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
<h4 id="Example_.232.3A_A_practical_instantiation_.E2.80.93_Daemon.buildAround()">Example #2: A practical instantiation – <code>Daemon.buildAround()</code></h4>
<div style="height: 400px; margin-bottom: 12px; overflow: auto;">
  <pre class="brush: html">
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
&lt;title&gt;Daemon.buildAround(&amp;hellip;)&lt;/title&gt;
&lt;script type="text/javascript" src="fork.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="daemons-methods.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
&nbsp;
&nbsp;/*\
&nbsp;|*|
&nbsp;|*|&nbsp; :: Daemon.buildAround(@context[, @rate, @length]) ::
&nbsp;|*|
&nbsp;|*|&nbsp; Returns a new daemon built around a @context object. The @context object must cointain *at least*
&nbsp;|*|&nbsp; a "perform" property pointing to what you want to be the @callback function of the daemon.
&nbsp;|*|&nbsp; It can also optionally contain a "create" and a "prepare" properties pointing respectively to the
&nbsp;|*|&nbsp; two functions you want to be the @init and @onstart functions of Daemon constructor's arguments.
&nbsp;|*|&nbsp; The @context object will be also the *this* object of your callback function. So you can populate
&nbsp;|*|&nbsp; it with any custom properties and methods. The only required one property is "perform".
&nbsp;|*|&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;|*|&nbsp;&nbsp;&nbsp; Sample usage:
&nbsp;|*|
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var myDaemon = Daemon.buildAround({
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "customProperty": [custom value],
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "myCustomMethod": function () { [custom code] },
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "anotherCustomProperty": [custom value],
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "etc.": "etc."
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "create": function () { [custom code] },&nbsp; // optional
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "prepare": function () { [custom code] },&nbsp; // optional
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "perform": function () { [custom code] },&nbsp; // required
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }, 200, 30);
&nbsp;|*|
&nbsp;\*/
&nbsp;
var sText = "Do you feel lucky, punk?", oUnhide = Daemon.buildAround({
&nbsp; // http://tyleregeto.com/text-animation-in-javascript
&nbsp; "letters": [],
&nbsp; "numletters": 0,
&nbsp; "clock": 0,
&nbsp; "interval": 0.0,
&nbsp; "delta": 33,
&nbsp; "letters": [],
&nbsp; "pool": ["0","1","2","3","4","5","6","7","8","9"],
&nbsp; "target": document.createElement("p"),
&nbsp; "create": function () {
&nbsp;&nbsp;&nbsp; // build letters list
&nbsp;&nbsp;&nbsp; this.target.textContent = "";
&nbsp;&nbsp;&nbsp; this.letters.length = 0;
&nbsp;&nbsp;&nbsp; for (var oSpan, oLetter, nLetter = 0, nLen = sText.length; nLetter &lt; nLen; nLetter++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oSpan = document.createElement("span");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oSpan.textContent = sText[nLetter];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter = { "elem": oSpan, "parent": this.target };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.letters.push(oLetter);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.index = this.numletters;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.elem.style.position = "relative";
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.val = oLetter.elem.textContent;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.numletters++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.target.appendChild(oSpan);
&nbsp;&nbsp;&nbsp; }
&nbsp; },
&nbsp; "perform": function (nIndex, nLength, bBackw) {
&nbsp;&nbsp;&nbsp; for (var oLetter, nLetter = 0; nLetter &lt; this.letters.length; nLetter++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter = this.letters[nLetter];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nLength &lt; nIndex &amp;&amp; this.clock + this.delta &lt; this.interval) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clock += this.delta;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.clock = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.elem.textContent = nIndex / nLength - oLetter.index / this.numletters &gt;= 0 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.val
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : this.pool[parseInt(Math.random() * this.pool.length)];
&nbsp;&nbsp;&nbsp; }
&nbsp; }
}, 33, 30);
&nbsp;
onload = function () {
&nbsp; oUnhide.owner.target.id = "animate-me";
&nbsp; document.body.appendChild(oUnhide.owner.target);
&nbsp; oUnhide.play();
};
&nbsp;
&lt;/script&gt;
&nbsp;
&lt;style type="text/css"&gt;
body {
&nbsp; font-family: monospace, sans-serif;
&nbsp; background: #DDDDDD;
&nbsp; overflow: hidden;
}
&nbsp;
#animate-me {
&nbsp; margin: 50px;
&nbsp; font-size: 20px;
&nbsp; line-height: 20px;
}
&lt;/style&gt;
&lt;/head&gt;
&nbsp;
&lt;body&gt;
&nbsp;
&lt;h1&gt;Daemon.buildAround()&lt;/h1&gt;
&nbsp;
&lt;p&gt;&lt;button onclick="oUnhide.skipTo(11);"&gt;skipTo(11)&lt;/button&gt;
&lt;button onclick="oUnhide.makeSteps(29);"&gt;makeSteps(29)&lt;/button&gt;
&lt;button onclick="oUnhide.fixPosition(-13);"&gt;fixPosition(-13)&lt;/button&gt;
&lt;button onclick="oUnhide.play();"&gt;play&lt;/button&gt;
&lt;button onclick="oUnhide.turn();"&gt;turn&lt;/button&gt;
&lt;button onclick="oUnhide.pause();"&gt;pause&lt;/button&gt;
&lt;button onclick="oUnhide.reversePlay();"&gt;reversePlay&lt;/button&gt;
&lt;button onclick="oUnhide.reversals = 2;alert('changed');"&gt;two reversals&lt;/button&gt;
&lt;button onclick="oUnhide.makeLoop();alert('changed');"&gt;makeLoop&lt;/button&gt;
&lt;button onclick="oUnhide.unmakeLoop();alert('changed');"&gt;unmakeLoop&lt;/button&gt;
&lt;button onclick="oUnhide.close();"&gt;close&lt;/button&gt;
&lt;button onclick="oUnhide.reclose();"&gt;reclose&lt;/button&gt;&lt;br /&gt;
frame rate: &lt;input type="text" id="vello" value="33" style="width: 40px;" onkeypress="return event.charCode===0||/\d/.test(String.fromCharCode(event.charCode));" onkeyup="if(isFinite(this.value)&amp;&amp;Number(this.value)&gt;0){oUnhide.setRate(this.value);}" /&gt;&lt;/p&gt;
&nbsp;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
<h4 id="Example_.233.3A_A_safe_(without_setInterval)_instantiation_.E2.80.93_new_Daemon.safe()">Example #3: A <em>safe</em> (without <code>setInterval</code>) instantiation – <code>new Daemon.safe()</code></h4>
<div style="height: 400px; margin-bottom: 12px; overflow: auto;">
  <pre class="brush: html">
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
&lt;title&gt;new Daemon.safe(&amp;hellip;)&lt;/title&gt;
&lt;script type="text/javascript" src="fork.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="daemon-safe.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="daemons-methods.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
&nbsp;
function perform (nIndex, nLength, bBackw) {
&nbsp; // http://tyleregeto.com/text-animation-in-javascript
&nbsp; for (var oLetter, nLetter = 0; nLetter &lt; aLetters.length; nLetter++) {
&nbsp;&nbsp;&nbsp; oLetter = aLetters[nLetter];
&nbsp;&nbsp;&nbsp; var nDist = nMaxDist - nMaxDist * nIndex / nLength;
&nbsp;&nbsp;&nbsp; oLetter.pos += 0.08;
&nbsp;&nbsp;&nbsp; oLetter.elem.style.top = Math.sin(oLetter.pos) * nDist + "px";
&nbsp;&nbsp;&nbsp; oLetter.elem.style.left = Math.cos(oLetter.pos) * nDist * 5 + "px";
&nbsp; }
}
&nbsp;
function prepare () {
&nbsp; // build letters list
&nbsp; // http://tyleregeto.com/text-animation-in-javascript
&nbsp; this.textContent = "";
&nbsp; aLetters.length = 0; &nbsp;
&nbsp; for (var oSpan, oLetter, nLetter = 0, nLen = sText.length; nLetter &lt; nLen; nLetter++) {
&nbsp;&nbsp;&nbsp; oSpan = document.createElement("span");
&nbsp;&nbsp;&nbsp; oSpan.textContent = sText[nLetter];
&nbsp;&nbsp;&nbsp; oLetter = { "elem": oSpan, "parent": this };
&nbsp;&nbsp;&nbsp; aLetters.push(oLetter);
&nbsp;&nbsp;&nbsp; oLetter.pos = Math.random() * 50;
&nbsp;&nbsp;&nbsp; oLetter.elem.style.position = "relative";
&nbsp;&nbsp;&nbsp; this.appendChild(oSpan);
&nbsp; }
}
&nbsp;
var
&nbsp; nMaxDist = 25, aLetters = [], sText = "Do you feel lucky, punk?",
&nbsp; oRecompose = new Daemon.safe(document.createElement("p"), perform, 33, 30, prepare);
&nbsp;
onload = function () {
&nbsp; oRecompose.owner.id = "perform-me";
&nbsp; document.body.appendChild(oRecompose.owner);
&nbsp; oRecompose.play();
};
&nbsp;
&lt;/script&gt;
&nbsp;
&lt;style type="text/css"&gt;
body {
&nbsp; font-family: monospace, sans-serif;
&nbsp; background: #DDDDDD;
&nbsp; overflow: hidden;
}
&nbsp;
#perform-me {
&nbsp; margin: 50px;
&nbsp; font-size: 20px;
&nbsp; line-height: 20px;
}
&lt;/style&gt;
&lt;/head&gt;
&nbsp;
&lt;body&gt;
&nbsp;
&lt;h1&gt;new Daemon.safe(&lt;em&gt;@thisObject&lt;/em&gt;, &lt;em&gt;@callback&lt;/em&gt;[, &lt;em&gt;@rate&lt;/em&gt;, &lt;em&gt;@length&lt;/em&gt;, &lt;em&gt;@init&lt;/em&gt;, &lt;em&gt;@onstart&lt;/em&gt;])&lt;/h1&gt;
&nbsp;
&lt;p&gt;&lt;button onclick="oRecompose.skipTo(11);"&gt;skipTo(11)&lt;/button&gt;
&lt;button onclick="oRecompose.makeSteps(29);"&gt;makeSteps(29)&lt;/button&gt;
&lt;button onclick="oRecompose.fixPosition(-13);"&gt;fixPosition(-13)&lt;/button&gt;
&lt;button onclick="oRecompose.play();"&gt;play&lt;/button&gt;
&lt;button onclick="oRecompose.turn();"&gt;turn&lt;/button&gt;
&lt;button onclick="oRecompose.pause();"&gt;pause&lt;/button&gt;
&lt;button onclick="oRecompose.reversePlay();"&gt;reversePlay&lt;/button&gt;
&lt;button onclick="oRecompose.reversals = 2;alert('changed');"&gt;two reversals&lt;/button&gt;
&lt;button onclick="oRecompose.makeLoop();alert('changed');"&gt;makeLoop&lt;/button&gt;
&lt;button onclick="oRecompose.unmakeLoop();alert('changed');"&gt;unmakeLoop&lt;/button&gt;
&lt;button onclick="oRecompose.close();"&gt;close&lt;/button&gt;
&lt;button onclick="oRecompose.reclose();"&gt;reclose&lt;/button&gt;&lt;br /&gt;
frame rate: &lt;input type="text" id="vello" value="33" style="width: 40px;" onkeypress="return event.charCode===0||/\d/.test(String.fromCharCode(event.charCode));" onkeyup="if(isFinite(this.value)&amp;&amp;Number(this.value)&gt;0){oRecompose.setRate(this.value);}" /&gt;&lt;/p&gt;
&nbsp;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
<h4 id="Example_.234.3A_A_practical_and_safe_(without_setInterval)_instantiation_.E2.80.93_Daemon.safe.buildAround()">Example #4: A practical and <em>safe</em> (without <code>setInterval</code>) instantiation – <code>Daemon.safe.buildAround()</code></h4>
<div style="height: 400px; margin-bottom: 12px; overflow: auto;">
  <pre class="brush: html">
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
&lt;title&gt;Daemon.safe.buildAround(&amp;hellip;)&lt;/title&gt;
&lt;script type="text/javascript" src="fork.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="daemon-safe.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="daemons-methods.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
&nbsp;
&nbsp;/*\
&nbsp;|*|
&nbsp;|*|&nbsp; :: Daemon.safe.buildAround(@context[, @rate, @length]) ::
&nbsp;|*|
&nbsp;|*|&nbsp; Returns a new daemon built around a @context object. The @context object must cointain *at least*
&nbsp;|*|&nbsp; a "perform" property pointing to what you want to be the @callback function of the daemon.
&nbsp;|*|&nbsp; It can also optionally contain a "create" and a "prepare" properties pointing respectively to the
&nbsp;|*|&nbsp; two functions you want to be the @init and @onstart functions of Daemon constructor's arguments.
&nbsp;|*|&nbsp; The @context object will be also the *this* object of your callback function. So you can populate
&nbsp;|*|&nbsp; it with any custom properties and methods. The only required one property is "perform".
&nbsp;|*|&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;|*|&nbsp;&nbsp;&nbsp; Sample usage:
&nbsp;|*|
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var myDaemon = Daemon.safe.buildAround({
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "customProperty": [custom value],
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "myCustomMethod": function () { [custom code] },
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "anotherCustomProperty": [custom value],
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "etc.": "etc."
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "create": function () { [custom code] },&nbsp; // optional
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "prepare": function () { [custom code] },&nbsp; // optional
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "perform": function () { [custom code] },&nbsp; // required
&nbsp;|*|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }, 200, 30);
&nbsp;|*|
&nbsp;\*/
&nbsp;
var sText = "Do you feel lucky, punk?", oUnhide = Daemon.safe.buildAround({
&nbsp; // http://tyleregeto.com/text-animation-in-javascript
&nbsp; "letters": [],
&nbsp; "numletters": 0,
&nbsp; "clock": 0,
&nbsp; "interval": 0.0,
&nbsp; "delta": 33,
&nbsp; "letters": [],
&nbsp; "pool": ["0","1","2","3","4","5","6","7","8","9"],
&nbsp; "target": document.createElement("p"),
&nbsp; "create": function () {
&nbsp;&nbsp;&nbsp; // build letters list
&nbsp;&nbsp;&nbsp; this.target.textContent = "";
&nbsp;&nbsp;&nbsp; this.letters.length = 0;
&nbsp;&nbsp;&nbsp; for (var oSpan, oLetter, nLetter = 0, nLen = sText.length; nLetter &lt; nLen; nLetter++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oSpan = document.createElement("span");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oSpan.textContent = sText[nLetter];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter = { "elem": oSpan, "parent": this.target };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.letters.push(oLetter);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.index = this.numletters;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.elem.style.position = "relative";
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.val = oLetter.elem.textContent;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.numletters++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.target.appendChild(oSpan);
&nbsp;&nbsp;&nbsp; }
&nbsp; },
&nbsp; "perform": function (nIndex, nLength, bBackw) {
&nbsp;&nbsp;&nbsp; for (var oLetter, nLetter = 0; nLetter &lt; this.letters.length; nLetter++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter = this.letters[nLetter];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nLength &lt; nIndex &amp;&amp; this.clock + this.delta &lt; this.interval) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clock += this.delta;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.clock = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.elem.textContent = nIndex / nLength - oLetter.index / this.numletters &gt;= 0 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oLetter.val
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : this.pool[parseInt(Math.random() * this.pool.length)];
&nbsp;&nbsp;&nbsp; }
&nbsp; }
}, 33, 30);
&nbsp;
onload = function () {
&nbsp; oUnhide.owner.target.id = "animate-me";
&nbsp; document.body.appendChild(oUnhide.owner.target);
&nbsp; oUnhide.play();
};
&nbsp;
&lt;/script&gt;
&nbsp;
&lt;style type="text/css"&gt;
body {
&nbsp; font-family: monospace, sans-serif;
&nbsp; background: #DDDDDD;
&nbsp; overflow: hidden;
}
&nbsp;
#animate-me {
&nbsp; margin: 50px;
&nbsp; font-size: 20px;
&nbsp; line-height: 20px;
}
&lt;/style&gt;
&lt;/head&gt;
&nbsp;
&lt;body&gt;
&nbsp;
&lt;h1&gt;Daemon.safe.buildAround()&lt;/h1&gt;
&nbsp;
&lt;p&gt;&lt;button onclick="oUnhide.skipTo(11);"&gt;skipTo(11)&lt;/button&gt;
&lt;button onclick="oUnhide.makeSteps(29);"&gt;makeSteps(29)&lt;/button&gt;
&lt;button onclick="oUnhide.fixPosition(-13);"&gt;fixPosition(-13)&lt;/button&gt;
&lt;button onclick="oUnhide.play();"&gt;play&lt;/button&gt;
&lt;button onclick="oUnhide.turn();"&gt;turn&lt;/button&gt;
&lt;button onclick="oUnhide.pause();"&gt;pause&lt;/button&gt;
&lt;button onclick="oUnhide.reversePlay();"&gt;reversePlay&lt;/button&gt;
&lt;button onclick="oUnhide.reversals = 2;alert('changed');"&gt;two reversals&lt;/button&gt;
&lt;button onclick="oUnhide.makeLoop();alert('changed');"&gt;makeLoop&lt;/button&gt;
&lt;button onclick="oUnhide.unmakeLoop();alert('changed');"&gt;unmakeLoop&lt;/button&gt;
&lt;button onclick="oUnhide.close();"&gt;close&lt;/button&gt;
&lt;button onclick="oUnhide.reclose();"&gt;reclose&lt;/button&gt;&lt;br /&gt;
frame rate: &lt;input type="text" id="vello" value="33" style="width: 40px;" onkeypress="return event.charCode===0||/\d/.test(String.fromCharCode(event.charCode));" onkeyup="if(isFinite(this.value)&amp;&amp;Number(this.value)&gt;0){oUnhide.setRate(this.value);}" /&gt;&lt;/p&gt;
&nbsp;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
<h2 id="See_also">See also</h2>
<ul>
  <li><a href="/en-US/docs/JavaScript/Timers" title="/en-US/docs/JavaScript/Timers">JavaScript timers</a>,</li>
  <li><a href="https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout" title="/en-US/docs/DOM/window.setTimeout"><code>setTimeout()</code></a>,</li>
  <li><a href="https://developer.mozilla.org/en-US/docs/DOM/window.setInterval" title="/en-US/docs/DOM/window.setInterval"><code>setInterval()</code></a>,</li>
  <li><a href="https://developer.mozilla.org/en-US/docs/DOM/window.clearTimeout" title="/en-US/docs/DOM/window.clearTimeout"><code>clearTimeout()</code></a>,</li>
  <li><a href="https://developer.mozilla.org/en-US/docs/DOM/window.clearInterval" title="/en-US/docs/DOM/window.clearTimeout"><code>clearInterval()</code></a>,</li>
  <li><a href="https://developer.mozilla.org/en-US/docs/DOM/window.requestAnimationFrame" title="en-US/docs/DOM/window.requestAnimationFrame">requestAnimationFrame()</a>.</li>
</ul>
Revert to this revision