AJS_ODL User-Guide

AUDIO/VIDEO

AJS_ODL caters for the media-related elements introduced by HTML 5, thus allowing you to cause the automatic retrieval of audio and video content when a call is made to a given method in your application.

LoadDefs that contain the AUDIO or VIDEO value for their LoadMethod properties causes AJS_ODL to create the corresponding HTML element, the src attribute of which it sets to the value of the URL in question. That element is passed to the onCreation event-handler for the LoadDef in question, along with a reference to that LoadDef. The handler is then free to insert the element into an arbitrary location in the DOM hierarchy. Where the LoadDef's URLs property contains more than one URL, an audio/video element is created for each, where AJS_ODL will call onCreation for each element that comes into being.

If the user agent cannot retrieve the audio/video resource because, for example, it does not exist at the location to which the corresponding URL refers, it should call the onerror handler for the element, which will cause AJS_ODL to call in turn any onError handler that you provided in the LoadDef.

Note that you can use the Attributes property in a LoadDef to modify various parameters associated with audio/video elements, and to provide handlers for the many media-element events that HTML5 defines.

Example 11 demonstrates these points.

Note also that <audio>/<video> elements in a given tract of HTML can be complex in that they may contain <source> and <track> etc. child-elements. The details of these are too complex to permit their simple-representation within a LoadDef, so it the responsiblity of the onCreation handler for the LoadDef in question to generate such child-elements as are needed and to append them to the <audio>/<video> element that AJS_ODL passes.

If you are using <source> and <track> elements such that the parent <audio>/<video> does not need a value for its src attribute, then you should use an empty string as the value of the corresponding URL (the ValidationDef in AJS_ODL.val.js does not validate the contents of URL strings).

Contents AUDIO/VIDEO
EMBED
IFRAME
IMG
LINK
OBJECT
SCRIPT
XHR
XHR Queueing and Dispatch

 // -- Example 11 -------------------------------------------------------------

 var MyObj =
    {
    method_A : function () { }
    };

 AJS_ODL.applyLoadDef (MyObj,
    {
    LoadMethod        :  "VIDEO",
    URLs              : ["MyVideo.mp4"],
    Attributes        :
       {
       autoplay       :  "autoplay",

       loadstart      :   function () { console.log ("loadstart executed");      },
       loadeddata     :   function () { console.log ("loadeddata executed");     },
       canplay        :   function () { console.log ("canplay executed");        },
       playing        :   function () { console.log ("playing  executed");       },
       canplaythrough :   function () { console.log ("canplaythrough executed"); },
       ended          :   function () { console.log ("ended  executed")          }

       },

    onCreation        :   function (LoadDef, Element)
       {
       document.body.appendChild (Element);
       console.log               ("Video element created");
       },

    onError           :   function (LoadDef, Element, Event)
       {
       // ...
       }

    });

 MyObj.method_A ();

 -- Output --------------------------------------------------------------------

 Video element created
 loadstart executed
 loadeddata executed
 canplay executed
 playing  executed
 canplaythrough executed
 ended  executed
      

EMBED

HTML5 also introduced the <embed> element, for which AJS_ODL also caters. As with the AUDIO/VIDEO LoadMethods, a value of EMBED causes AJS_ODL (upon execution of a method covered by that LoadDef) to create an <embed> element. It then sets the value of that element's src attribute to the value of a given member of the URL property of the LoadDef in question.

This causes the user agent to attempt retrieval of the resource referred to by the URL in question, and success in this respect causes AJS_ODL to call the onLoad event handler specified in the LoadDef, to which it passes a reference to the newly-created element, and a reference to the LoadDef. The application is then free to do what it wishes with the element. Remember that <embed> elements do not support the onload or onerror events, so they are disallowed in LoadDefs for this LoadMethod.

Example 12 demonstrates these ideas.


 // -- Example 12 -------------------------------------------------------------

 var MyObj =
    {
    method_A   : function () { }
    };

 AJS_ODL.applyLoadDef (MyObj,
    {
    LoadMethod :  "EMBED",
    URLs       : ["MyFlashAnimation.swf"],
    Attributes :
       {
       width   :  "640",
       height  :  "480"
       },

    onCreation : function (LoadDef, Element)
       {
       document.body.appendChild (Element);
       console.log               ("Embedded resource created");
       }

    });

 MyObj.method_A ();

 -- Output --------------------------------------------------------------------

 Embedded resource created
      

IFRAME

The IFRAME LoadMethod follows the same principles covered in the sections above, in that it creates an <iframe> element, sets its src attribute to the value of the URL in question, and calls the onCreation handler in the LoadDef (if it exists), passing references to the newly-created element and the LoadDef. If the LoadDef has an onLoad handler, AJS_ODL will also call that on successful retrieval of the resource in question.

Notably, however, all the major browsers call an iframe's onload handler even when the resource in question cannot be retrieved, This will cause AJS_ODL to call the LoadDef's onLoad handler too in such circumstances, rather than any onerror handler that it may possess (and so is not a defect on the part of AJS_ODL). Nevertheless, the component supports an onError handler for LoadDefs with a LoadMethod of IFRAME, in case other user agents do call an iframe element's onerror handler when the content cannot be retrieved.

Example 13 shows the IFRAME LoadMethod in action.


 // -- Example 13 -------------------------------------------------------------

 var MyObj =
    {
    method_A   : function () {  }
    };

 AJS_ODL.applyLoadDef (MyObj,
    {
    LoadMethod :  "IFRAME",
    URLs       : ["MyNestedPage.htm"],

    onCreation :  function (LoadDef, Element)
       {
       document.body.appendChild (Element);
       console.log               ("IFrame created");
       },

    onLoad     :  function (LoadDef, Element, Event)
       {
       console.log ("IFrame loaded");
       }

    });

 MyObj.method_A ();

 -- Output --------------------------------------------------------------------

 IFrame created
 IFrame loaded
      

IMG

The 'IMG' LoadMethod also centres on element synthesis, where execution of a method that is covered by the LoadDef in question causes AJS_ODL to create an <img> element and to then set its src attribute to the value of a URL in the LoadDef's URLs property. This causes the browser to retrieve the image automatically, and it follows that multiple values in the LoadDef's URLs property will cause the creation of multiple <img> elements.

As with all other LoadMethods (except 'XHR'), if the LoadDef possesses an Attributes property, the values for each attribute listed are assigned to the img element before AJS_ODL assigns the URL in question to its src attribute.

On creation of the element, AJS_ODL calls the onCreation handler, and successful retrieval of a given image causes subsequent execution of the the function referred to by the onLoad property in the LoadDef. If the LoadDef possesses multiple URLs, the onLoad event will be called for each image as and when they arrive on the client, and if the browser cannot retrieve the image, or if the image data is malformed in some way, AJS_ODL calls the function referred to by the onError property of the LoadDef in question.


 // -- Example 14 -------------------------------------------------------------

 var MyObj     =
    {
    method_A   : function () {  }
    };

 var LoadDef   =
    {
    MethodNames: ["method_A"],
    LoadMethod :  'IMG',
    URLs       : ['MyPicture.jpg', 'MyNonExistentPicture.jpg'],

    onCreation :   function (LoadDef, Element)
       {
       document.body.appendChild (Element);
       console      .log         ("Image element created");
       },

    onLoad     :   function (LoadDef, Element, Event)
       {
       console.log ("Image retrieved");
       },

    onError    :   function (LoadDef, Element, Event)
       {
       console.log ("Image retrieval failed");
       }

    };

 AJS_ODL.applyLoadDef (MyObj, LoadDef);

 MyObj  .method_A     ();

 -- Output --------------------------------------------------------------------

 Image element created
 Image element created
 Image retrieved
 Image retrieval failed
      

LINK

To load CSS code, you should use a value of 'LINK' for the LoadMethod property of the LoadDef in question (but do remember that a <link> element can be used to refer to external resources other than CSS files). A call to a method covered by such a LoadDef causes AJS_ODL to create a <link> element, and to then set its href attribute to the value of a URL in the LoadDef's URLs property, thus causing the user agent to retrieve the relevant resource.

As with 'SCRIPT' (see below), a value of 'LINK' for a LoadDef's LoadMethod property causes AJS_ODL to inject the newly-created link element into the head element of the page in question. This is the only legal place that a link element can reside, and so an onCreation property in the corresponding LoadDef is redundant and therefore disallowed (and which the validation code in AJS_ODL.val.js will trap).

Assuming that the element refers to a CSS file, successful retrieval of the code causes the user agent to evaluate and apply the style-rules it contains, and causes AJS_ODL to call the function referred to by the onLoad property (if present) in the associated LoadDef, passing a reference to the newly-created element, and a reference to the LoadDef.

If the code cannot be retrieved (because of, say, an unreachable URL) or if it is malformed in some way then AJS_ODL should call the onError handler (again, if present in the LoadDef), passing the Event object that was passed to the onerror handler that AJS_ODL attached to the link element, along with a reference to the element-object and a reference to the LoadDef in question.

Example 15 shows the use of the 'LINK' LoadMethod.

Given that a <link> element may refer to a resource other than CSS, do note that it is your responsiblity to set the rel and media attributes of the element in question by means of the Attributes property of the LoadDef in question, as Example 15 illustrates. Failure to do this will prevent the user agent from evaluating the resource, which means that, in the case of CSS code, no changes to page style and/or layout will occur, even if the resource has been retrieved and is well-formed.


 // -- Example 15 -------------------------------------------------------------

 var MyObj     =
    {
    method_A   : function () { console.log ("method_A executed"); }
    };

 var LoadDef   =
    {
    LoadMethod :  "LINK",
    URLs       : ["MyStyleSheet.css"],

    onLoad     :  function (LoadDef, Element, Event) { console.log ("onLoad executed");  },
    onError    :  function (LoadDef, Element, Event) { console.log ("onError executed"); },

    Attributes :
       {
       rel     : "stylesheet",
       type    : "text/css",
       media   : "all"
       }

    };

 AJS_ODL.applyLoadDef (MyObj, LoadDef);

 MyObj  .method_A     ();

 -- Output --------------------------------------------------------------------

 method_A executed
 onLoad executed
      

OBJECT

The <object> tag in HTML represents an embeddable resource (for which the <embed> element is a more-modern alternative), and AJS_ODL caters for this in the form of the 'OBJECT' LoadMethod. As with the other LoadMethods considered above, this is an element-synthesis method, meaning that AJS_ODL will create an <object> element, the data attribute of which it will set to the URL in question. After assigning to the element any values in the LoadDef's Attributes property (if present), it calls the onCreation handler, passing references to the newly-created element and the LoadDef itself.

As with the other element-synthesis methods, the call to onCreation leaves your code free to insert the element into the DOM hierarchy for the page in question at an arbitrary point, as Example 16 shows.

Note that <object> elements may contain children such as <param> elements. As with the AUDIO/VIDEO LoadMethods, your onCreation handler should create and assign whatever child elements the <object> element should contain.

Note also that HTML does not define onload or onerror event-handlers for <object> elements, so it is not possible to detect success or failure on the part of the user agent in its attempt to retrieve resources when using this LoadMethod.


 // -- Example 16 -------------------------------------------------------------

 var MyObj      =
    {
    method_A    : function () {  }
    };

 AJS_ODL.applyLoadDef (MyObj,
    {
    LoadMethod  :  "OBJECT",
    URLs        : ["MyFlashAnimation.swf"],
    Attributes  :
       {
       width    :  "640",
       height   :  "480",
       type     :  "application/x-shockwave-flash"
       },

    onCreation  : function (LoadDef, Element)
       {
       document.body.appendChild (Element);
       console.log               ("Object resource created");
       }

    });

 MyObj.method_A ();

 -- Output --------------------------------------------------------------------

 Object resource created
      

SCRIPT

The final element-synthesis loading-method that AJS_ODL supports allows you to load JavaScript code on-demand by means of 'script-element injection' (known colloquially as the 'Script-Tag Hack'), and is selected by providing a LoadMethod property of 'SCRIPT'. This causes AJS_ODL to create a <script> element, and to then set its src attribute to the value of a particular URL, after which AJS_ODL inserts the element into the head element in the DOM hierarchy for the page in question.

This causes the browser to download and evaluate the corresponding JavaScript code, and to thus introduce that code's functionality into the execution environment (as pointed out elswhere in this guide, multiple URLs for a given LoadDef cause this process to occur multiple times). On successful retrieval, AJS_ODL calls the function referred to by the onLoad property in the LoadDef, passing the browser-generated Event object for that event, and a reference to the newly-created script element.

If the code cannot be retrieved successfully, because of something amiss in the URL, or because the code is ill-formed, AJS_ODL should call the LoadDef's onError handler (if present), passing the browser-generated Event object, and a reference to the newly-created element.

Example 17, a slightly more detailed implementation of Example 6 shows the use of the 'SCRIPT' LoadMethod.

Note that HTML5 defines an asynch attribute for script elements, the behaviour of which in interaction with other attributes such as defer is rather involved. In essence, however, providing a value of false for this attribute allows you to enforce that multiple script-elements are evaluated in the order in which the user agent encounters them. AJS_ODL issues requests in the order in which the respective URLs are listed in the URLs property of a given LoadDef, so, if you wish the user agent to evaluate in that order the code bodies that are retrieved, give the LoadDef an Asynch property with a value of false.

Note, however, that you should not provide an async attribute in any Attributes property that the LoadDef may possess. XHR retrieval can be asynchronous, and so the Async property also plays a role in the 'XHR' LoadMethod, which is why async is disallowed in Attributes properties.

Note too that there is an alternative to using the 'SCRIPT' LoadMethod to introduce JavaScript code into an application, which still involves the synthesisis and injection of a <script> element, but which relies on the use of XHR to retrieve the code in question. This is explored in the next section.


 // -- Contents of MyOtherObj.js ----------------------------------------------

 var MyOtherObj =
    {
    method_A    : function () { console.log ("MyOtherObj.method_A Executed"); }
    };
      

 // -- Example 17 -------------------------------------------------------------

 var MyObj    =
    {
    method_A  :   function () { },
    method_B  :   function () { console.log ("MyObj.method_B Executed"); },
    method_C  :   function () { }
    };

 var MyObj_LoadDef =
   {
   URLs       : ["MyOtherObj.js"],
   LoadMethod :  "SCRIPT",

   onLoad     :   function (LoadDef, Element, Event) { MyOtherObj.method_A ();                        },
   onError    :   function (LoadDef, Element, Event) { console   .log      ("Script failed to load"); }

   };

 AJS_ODL.applyLoadDef (MyObj, MyObj_LoadDef);

 MyObj  .method_B     ();

 -- Output --------------------------------------------------------------------

 MyObj.method_B Executed
 MyOtherObj.method_A Executed
      

XHR

The final, most flexible, and thus most powerful LoadMethod supported by AJS_ODL does not involve element injection, but pivots on the use of an XHR (XMLHTTPRequest) object to communicate with the server. Note that upon instantiation, AJS_ODL creates at least one XHR object (see below), which it re-uses for all subsequent XHR-based communications. That is: it does not instantiate and then drop (for subsequent garbage-collection) a new XHR object for each transaction (a most inefficient approach).

XHR-based transactions are selected by specifying a value of 'XHR' for the LoadMethod property in a given LoadDef. Execution of methods that are subject to such a LoadDef causes AJS_ODL to issue an XHR request to the server, where the communication is asynchronous by default unless you force synchrony by furnishing the LoadDef with an Asynch property with a value of false. Do note here, however, that synchronous XHR-transactions are discouraged because memory- and event-leakage can occur when using this mode, and remember also that they cause the user agent to block until the server responds.

Remember that, if there is more than one URL in the LoadDef's URLs property, and the LoadMethod is 'XHR', AJS_ODL will dispatch a request to each in turn in the order in which they are stated in the URLs property (see the XHR Queueing and Dispatch section below for more information on this issue).

As with the other LoadMethods, successful retrieval causes AJS_ODL to call the onLoad property of the LoadDef in question. The difference here, however, is that it passes the raw XHR-object that was used to effect the transaction, and a reference to the LoadDef that directed the loading attempt (rather than an event object etc.). Your onLoad handler is then free to extract whatever information it sees fit from the XHR object, such as the responseText, response and responseXML properties.

Failure of the XHR transaction (through, say, a malformed URL) will cause AJS_ODL to call the function referred to by the LoadDef's onError property, to which it passes the XHR object and a reference to the LoadDef that directed the transaction. Similarly, if the transaction times-out, AJS_ODL will call the function referred to by the onTimeout property of the LoadDef in question (if present), passing a reference to the LoadDef. By default, the timeout delay is 30 seconds, but you can override this on a per-LoadDef basis by including a TimeoutDelay property in the LoadDef in question. This property is redundant where the LoadDef provides an Asynch property with a value of false, and using AJS_ODL.val.js will enable you to trap such a condition.

Do note that your application should use the XHR object passed to a given handler only passively. That is, it should not attempt to use it to launch another transaction, as this will not work, and, even if it did, it would conflict with AJS_ODL's queue-and-dispatch mechanism (see below).

Example 18 illustrates these essential points.

If you wish to retrieve non-textual data, such as binary objects, you can give a LoadDef a MimeType property, set to the value of an appropriate string. You can also use the ResponseType property to the same effect (although this is a more-recent addition to the W3C XHR-recommendation, and so browser support may vary). AJS_ODL will assign the value you give for this property directly to the responseType property of the underlying XHR object.


 // -- Contents of MyJSONObj.json ---------------------------------------------

    {
    "Father"      : { "Name" : "Homer", "Gender" : "M" },
    "Mother"      : { "Name" : "Marge", "Gender" : "F" },
    "FirstChild"  : { "Name" : "Bart",  "Gender" : "M" },
    "SecondChild" : { "Name" : "Lisa",  "Gender" : "F" }
    }
      

 // -- Example 18 -------------------------------------------------------------

 var TestObj   =
    {
    method_A   : function () { }
    };

 var TestObj_LoadDef =
    {
    URLs       : ["MyJSONObj.json"],
    LoadMethod :  "XHR",

    onTimeout  :   function (LoadDef) { console.log ("Transaction timed out"); },
    onLoad     :   function (LoadDef, XHRObj)
       {
       var Data = JSON.parse (XHRObj.responseText);

       console.log ("Loaded - " + Data.SecondChild.Name + " is the Simpsons" second child (Woo Hoo).");

       },

    onError    :   function (LoadDef, XHRObj)
       {
       console.log ("Error " + XHRObj_status + " " + XHRObj_statusText);
       }

    };

 AJS_ODL.applyLoadDef (TestObj, TestObj_LoadDef);

 TestObj.method_A     ();

 -- Output --------------------------------------------------------------------

 Loaded - Lisa is the Simpsons' second child (Woo Hoo).
      

One advantage of the responseType property is that, by giving it a value of 'document', it allows you to retrieve ready-parsed HTML page-fragments. This is similar to the automatic parsing that occurs when XML data is retrieved, although do note that synchronous XHR transactions are impossible when retrieving HTML, which is not an AJS_ODL limitation (and using AJS_ODL.val.js will allow you to trap any LoadDefs that stipulate this).

If the transaction retrieved plain textual-data (such as a JSON string) then this will be carried in the responseText and response properties. Binary data will be carried unprocessed by the response property, and if the data was XML or HTML (where the responseType property was set to 'document') then the responseXML property will refer to the root of the tree structure that has been generated. Note that the reason for passing a reference to the LoadDef object is to facilitate the sharing of onLoad handlers between different LoadDefs.

As mentioned in the previous section, an alternative to using the SCRIPT loading method is to use the XHR LoadMethod to retrieve the code, where the onLoad handler creates a <script> element, inserts that into the <head> element for the page in question, and then sets the text attribute of the script element to the responseText argument that AJS_ODL passes to the onLoad handler.

Example 19 shows this technique.


 // -- Contents of MyOtherObj.js ----------------------------------------------

 var MyOtherObj =
    {
    method_A    : function () { console.log ("MyOtherObj.method_A Executed"); }
    };
      

 // -- Example 19 -------------------------------------------------------------

 var MyObj =
    {
    method_A   : function () { }
    };

 AJS_ODL.applyLoadDef (MyObj,
    {
    URLs       : ["MyOtherObj.js"],
    LoadMethod :  "XHR",

    onLoad     :   function (LoadDef, XHRObj)
       {
       var Element = document.createElement ("script");

       document.getElementsByTagName ("head")[0].appendChild (Element);

       Element.text = XHRObj.responseText;

       MyOtherObj.method_A ();

       },

    onError    :   function (LoadDef, XHRObj)
       {
       console.log ("Loading operation failed");
       }

    });

 MyObj.method_A ();

 -- Output --------------------------------------------------------------------

 MyOtherObj.method_A Executed
      

XHR Queuing and Dispatch

It is not possible to conduct an XHR transaction through an XHR object that is already handling a prior transaction. That is: the function to which a given XHR object's onreadystatechange property refers – the function that handles the server's response, and which calls in turn a given LoadDef's onLoad handler – cannot launch a new transaction through that object directly, and so nor can your onLoad handler or any functions that it calls.

This has implications for onLoad handlers that call an object-method to which a LoadDef has also been applied, where that LoadDef also stipulates the 'XHR' LoadMethod. In this situation, the only solution is for second (or third etc.) XHR transactions to be posted to a queue, such that, when the onLoad handler for the first transaction returns, the onreadystatechange handler sets a timer that fires after just a brief delay following completion of the initial transaction, thus causing the dispatch of the next XHR request.

Given that this has performance implications for certain classes of application, AJS_ODL is designed to operate with more than one XHR object at a time, such that a request that is posted to the queue is dispatched immediately should an XHR object be available, otherwise it is enqueued until a prior transaction completes.

By default, AJS_ODL creates two XHR objects at start-up, but you have the freedom to change this, and to change the time that elapses between successive dispatches. Such configuration is effected by setting two constants in the code for AJS_ODL itself, and the relevant code statements are shown verbatim in Example 20.

Here, MaxDispachers denotes the number of XHR objects, and should be a positive integer greater than zero, and DispatchThrottle denotes the time in milliseconds between one tranaction completing and the next (if any, and assuming a free XHR object) being launched. This too should always be a positive integer – the larger the number, the longer the delay – and manipulating this value allows you to throttle the rate at which requests are dispatched (hence its name).

Obviously, it would be possible to implement these variables as arguments that you would pass to createAJS_ODL. This would make things more convenient for advanced users, but it would also complicate that function's signature for the sake of what is a rather abstruse issue, where the defaults should be adequate for most applications.

In essence, the ability to configure AJS_ODL in this way allows you to tune a given application in view of the XHR throughput that it is intended to handle, along with constraints imposed by server-side architecture, the limits on XHR instantiation that user agents may impose, and the degree to which other components in the application instantiate their own XHR objects. Metaphorically, it can be seen as the ability to change the number of cylinders in a car's engine, and its maximum RPM, at engine start-up, in order to achieve an optimum mix of performance, efficiency and other factors. (In truth, the queue-dynamics in your local post-office are the better model, but a bit of Lamborghini is a lot more fun).


 // -- Example 20 -------------------------------------------------------------

 var MaxDispatchers   =  2;   // Number of XHR objects created at start-up.
 var DispatchThrottle = 50;   // Time in milliseconds between the end of one transaction and the start of the next.
      

To understand the ramifications of this, consider a scenario where method_A calls method_B, which calls method_C in turn, where each method has a LoadDef attached, where the LoadMethod is 'XHR' for each, where each LoadDef possesses just one URL in its URLs property, and where the XHR transactions are asynchronous. Example 21 depicts this.

Here, an initial call to method_A will cause the loading prefix to execute, which will issue a request to the server on method_A's URL, following which the prefix will return, at which point method_A will execute. When that method makes a call to method_B, the loading prefix for that function will operate in the same way, and will issue a request to the URL that its URLs property dictates, after which method_B will execute, calling method_C, where, again, its loading prefix will get first crack at things, and will issue a third XHR request on the approprite URL.

If, in this scenario, AJS_ODL is configured to instantiate only one XHR object, then it will enqueue the method_B and method_C requests, where each request will be dispatched to the XHR object on a FIFO basis whenever that object become available. In this case, no request is issued until the previous one has completed (either successfully, or in some kind of error state such as a plain-old 404, or where it times out). This guarantees that each transaction will initiate and complete in the order in which it was issued (i.e. in this example, by the sequential invocation of method_A, method_B and then method_C), and it has the same effect (with none of the problems) as stipulating Asynch : false in each of the LoadDefs.

If, however, AJS_ODL is configured to use two XHR objects, the call to method_A will cause its associated request to be dispatched through one of those XHR objects, and the call to method_B will invoke a transaction that is conducted through the other. Both XHRs are thus rendered unavailable until their respective transactions complete, and so the call from method_B to method_C will cause method_C's XHR request to be enqueued until one of the transacting XHRs becomes available.

To develop this example further, if AJS_ODL has three XHRs, then none of the three requests will be queued, and if it has four XHRs, then one of those objects will go unused. In other words, the greater the number of XHR objects that AJS_ODL possesses, the lesser the time (ignoring server-response delay, and any latency in the system) a given request will sit waiting in the queue before being sent off. However, while the dispatcher guarantees to send requests in the order that the application serves them, irrespective of the number of XHR objects available, the inherent asynchrony of network communications means that more than one XHR will render it unable to guarantee the order in which the corresponding responses will return. You should consult the Concurrency section for discussion of the implications here.

Note that it follows from the points above that forcing all XHR transactions to be synchronous will defeat utterly AJS_ODL's queue-and-dispatch mechanism, and that any given synchronous transaction will block dispatch of all other pending transactions until that synchronous transaction has completed. Moreover, if you use synchronous requests exclusively, there is no point in AJS_ODL instantiating more than one XHR object, because only one will ever be used at a given time.


 // -- Example 21 -------------------------------------------------------------

 var MyFirstObj =
    {
    method_A : function () { MySecondObj.method_B (); }    // method_A calls method_B.
    };

 var MySecondObj =
    {
    method_B : function () { MyThirdObj.method_C (); }     // method_B calls method_C.
    };

 var MyThirdObj =
    {
    method_C : function () { }
    };

 AJS_ODL.applyLoadDef (MyFirstObj,                         // LoadMethod will be 'XHR' by default.
    {                                                      // Will apply implicitly to method_A.
    URLs       : ["SomeData.txt"],
    onLoad     :   function (LoadDef, XHRObj) { },
    onError    :   function (LoadDef, XHRObj) { }
    });

 AJS_ODL.applyLoadDef (MySecondObj,                        // LoadMethod will be 'XHR' by default.
    {                                                      // Will apply implicitly to method_B.
    URLs       : ["SomeMoreData.txt"],
    onLoad     :   function (LoadDef, XHRObj) { },
    onError    :   function (LoadDef, XHRObj) { }
    });

 AJS_ODL.applyLoadDef (MyThirdObj,                         // LoadMethod will be 'XHR' by default.
    {                                                      // Will apply implicitly to method_C.
    URLs       : ["YetMoreData.txt"],
    onLoad     :   function (LoadDef, XHRObj) { },
    onError    :   function (LoadDef, XHRObj) { }
    });

 MyFirstObj.method_A ();