DP_AJAX

The DP_AJAX library provides simple methods to manage multiple HTTP requests and XML responses.

  • The library has a very small footprint (only two global objects are created).
  • Multiple (but still asynchronous) HTTP calls can be joined together and fire a single handler when complete.
  • Multiple request pools can be instantiated in the same application if required (for example a “fast” pool might be created for user interface interaction while a “slow” pool might be created for automated logging).
  • Supports both adding custom HTTP headers (needed for many web services) to requests and accessing returned headers.
  • Supports GET, POST and both SOAP 1.0 and 1.2 calls.
  • Highly configurable. The number of request objects in the pool, the interval at which the request queue is checked, the timeout and the number of retry attempts for requests are user-configurable on a per-instance basis.
  • Optional Debugging and logging via DP_Debug (if available).

This component requires a JavaScript (ECMAScript) 1.3 (or better) environment and has been tested successfully on Internet Explorer 8+, Firefox 13+ and Google Chrome but should function on any modern browser.

Download

The component is available from GitHub:

All downloads and code are covered by our Source Code Policy.

Usage

The library consists of a single JavaScript file with a .JS extension.

Importing the Library

The library must be imported before it is used. To import the library use the <script> tag. For example:

<script type="text/javascript" src="DP_AJAX.js"></script>

Your path may vary depending on the location of the script on your server.

Some Terminology

There are some conceptual terms that will make understanding and using this object easier.

  • Call: A defined HTTP call (represented by a method, URL, parameters, etc.)
  • Caller: Callers are the individual HTTP objects that actually do most of the work. The specific objects used depend upon the environment. In FireFox, Chrome, IE 7+ and others these will be instances of the native XMLHttpRequest object while in older versions of IE these will be instances of the Microsoft.XMLHTTP ActiveX object. DP_AJAX manages callers automatically for you.
  • Request: A linked unit of one or more calls that, when complete, will trigger a specified handler function.
  • Pool: Pools run continuously once created and launch any requests added to their queues as callers become available. Pools can be defined with a number of callers and other configuration options.

The Basics

Once the library has been imported you may call any of the static Properties and Methods of the library. For example:

	MyPool = DP_AJAX.createPool();
	MyRequest = DP_AJAX.createRequest(Handler);
	

Once you have created an instance of the object you can use the Properties and Methods provided. Generally usage of the library will involve the same basic steps:

  • Create a request pool using the DP_AJAX.createPool() method.
  • Create one or more requests DP_AJAX.createRequest() method.
  • Add one or more calls to your requests using the RequestInstance.addCall() method. Once completed the requests will pass the data obtained to your defined handlers.
  • Continue create requests and adding calls as needed.

See the Examples section for further explanations and sample code.

General Recommendations

The DP_AJAX request pool object consolidates and controls the proliferation of HTTP request objects with an application. Considering this here are some general guidelines:

  • If possible pools should be instantiated and persisted within an application rather than creating and destroying them often.
  • The “correct” number of callers in a pool (as set by the CallerCount argument in the DP_AJAX.createPool() method) will vary according to the application needs. However in general a low number (2-6) will suit most applications very well. Larger numbers mean more resources dedicated to managing them and many platforms limit the total number of simultaneous requests allowed. Experiment with the number in your application to find the best balance.
  • Although seemingly counter-intuitive using only one caller object is sometimes beneficial. It will ensure that all of your calls are made in serial (that only one call is active at any time and requests are made in the order in which they were added to the queue). This can be very useful for applications where the target server is slow, overloaded or would otherwise benefit from such throttling.

Integration with DP_Debug

DP_AJAX features optional integration with DP_Debug. If the DP_Debug library is loaded and enabled (using the DP_Debug.enabled() method, see the documentation for more information) debugging and logging information will be displayed in the debugging console.

Properties and Methods

DP_AJAX

DP_AJAX has many static methods available and several of them produce instances of object with methods of the their own (documentation for these follow). DP_AJAX methods available:

Note arguments in square brackets are optional.

DP_AJAX.createPool()

Creates and returns a reference to an instance of a DP_AJAX request pool object (see below for information about available properties and methods of the instance). Request pools automatically manage any requests that are added to their queues.

Method Signature

DP_AJAX.createPool( [CallerCount], [Interval], [DefaultTimeout], [DefaultMaxAttempts] )

Arguments

This method has four arguments:

  • CallerCount: Number, Optional. Defaults to “4”. The number of caller objects to be instantiated. In effect the total number of simultaneous requests that can be made using the pool.
  • Interval: Number, Optional. Defaults to “200”. The number of milliseconds between scans of the queue. Lower numbers will react to additions and changes more quickly but use more processing resources.
  • DefaultTimeout: Number, Optional. Defaults to 0 (no timeout). The duration, in seconds, that represents the maximum time to attempt a request before .
  • DefaultMaxAttempts: Number, Optional. Defaults to “1” (do not retry). The number of times that a request should be reattempted in case of a failure response. (In this case “failure” is considered an HTTP result code of something other than 200 or 0).

Return

Object. An instance of a DP_AJAX request pool.

DP_AJAX.createRequest()

Creates and returns a reference to an instance of DP_AJAX request object (see below for information about available properties and methods of the instance).

Method Signature

DP_AJAX.createRequest( [SuccessHandler], [SuccessHandlerArgs], [ErrorHandler], [ErrorHandlerArgs], [AbortOnError], [SimpleResponses] )

Arguments

This method has six arguments:

  • SuccessHandler: Function reference, optional. A reference to the function which should be called upon successful completion of the request. When calling the handler the results of the HTTP call(s) will be passed as the first argument to the function. For requests with multiple calls an array of values is returned in the order the calls were added to the request, otherwise a single value is returned. The structure of the returned value(s) depend on the value of the SimpleResponses argument.
  • SuccessHandlerArgs: Array, optional. Functionally identical to the SuccessHandler argument above, but called when the request encounters an error.
  • ErrorHandler: Function reference, optional. A reference to the function which should be called upon request error. When calling the handler the results of the HTTP call(s) will be passed as the first argument to the function.
  • ErrorHandlerArgs: Array, optional. The contents of the array will be passed as additional arguments to the error handler function.
  • AbortOnError: Boolean, Optional. Defaults to true. Determines if all calls in the request should be aborted when one of the calls encounters and error. Only meaningful for multi-call requests.
  • SimpleResponses: Boolean, Optional. Defaults to true. Determines the type of responses passed to the handlers. If true the response is either an XML document containing the result (if available) or a string with the plain-text response. If “false” the response is an object with the following properties:
    • Status: The status of the completed HTTP call (for successful calls this will be “200”).
    • StatusText: Any text value associated with the HTTP status.
    • ResponseText: If available, the plain-text data returned by the HTTP call.
    • ResponseXML: If available, a platform-native XML document represented the data returned by the HTTP call.
    • Headers: An object whose property names/values represent the HTTP Header returned by the HTTP call.

Return

Boolean. Always returns “true”.

DP_AJAX.createXML()

Returns a new, platform-native XML document.

Method Signature

DP_AJAX.createXML( [RootName], [RootNamespaceURL] )

Arguments

This method has two arguments:

  • RootName: The name of the root tag (with or without a namespace prefix), optional. If provided the returned XML document will contain a single empty tag with this name.
  • RootNamespaceURL: URL, optional. If the passed RootName tag has a namespace prefix, pass the URL that identifies the namespace scheme here.

Return

A platform-native XML document.

DP_AJAX.loadXML()

A simplistic method to create and load an XML document via an HTTP call. For a more robust solution use a DP_AJAX Request pool.

Method Signature

DP_AJAX.loadXML( URL, [Async], [Handler] )

Arguments

This method has three arguments:

  • URL: String. The URL to call, required.
  • Async: Boolean. Optional (defaults to “true”). If “true” (the default) the call will be made asynchronously, if “false” the call will be made synchronously (note that synchronous call will halt all processing until the call completes and is generally only useful for simple testing).
  • Handler: Function reference, optional. A reference to the function which should be called upon completion of the request. When calling the handler the text results of the HTTP call will be passed as an argument to the function.

Return

A platform-native XML document. If the call was made asynchronously the doc will not be populated with data, if the call was made synchronously it will be loaded with the data upon return.

DP_AJAX.parseXML()

Attempts to convert the passed text into a platform-native XML document.

Method Signature

DP_AJAX.parseXML( Text )

Arguments

This method has one argument:

  • Text: A string representation of XML, required.

Return

A platform-native XML document (if successful) or null if an error occurs. Note that some implementations will return unexpected results (for example XML documents containing error information) it’s recommended that you test with malformed input to ensure regular results for your platform.

DP_AJAX.xmlToString()

Accepts a native XML document and returns a string representation.

Method Signature

DP_AJAX.xmlToString( XML )

Arguments

This method has one argument:

  • XML: A platform-native XML document, required.

Return

String. A plain-text representation of the passed XML.

DP_AJAX Request Pool

DP_AJAX Request Pools are generated using the DP_AJAX.createPool() method.

There are several properties available in a Request Pool however direct manipulation of these properties is discouraged:

  • ID: A system generated identification string for the pool used in debug output and logging. The form is “DP_AJAX_Pool_N” where N is an integer representing the count of instantiated pools.
  • Interval: The number of milliseconds between scans of the request queue.
  • DefaultTimeout: The default request timeout, in seconds.
  • DefaultMaxAttempts: The default number of request retry attempts.
  • CallerCount: The number of callers instantiated in the pool.
  • Callers: An array of all instantiated HTTP call objects.
  • Calls: An array containing all pending calls for all pending requests.

Request Pool methods available:

Note arguments in square brackets are optional.

PoolInstance.addRequest()

Adds a new request to the pool’s request queue.

Method Signature

PoolInstance.addRequest( Request )

Arguments

This method has one argument:

  • Request: A Request Object (as created with the DP_AJAX.createRequest method), required.

Return

Object, a reference to the current pool instance. This allows method chaining.

PoolInstance.clear()

Clears the pool’s request queue and, optionally, aborts any currently running calls.

Method Signature

PoolInstance.clear( [AbortRunningRequests] )

Arguments

This method has one argument:

  • AbortRunningRequests: Boolean, optional. Defaults to “false”. If True an attempt will be made to abort all currently running requests. If False only queued (not yet running) requests will be eliminated.

Return

Object, a reference to the current pool instance. This allows method chaining.

PoolInstance.isBusy()

Determines if the current pool is currently running any requests. Can be used to inform “Network Activity” interface indicators.

Method Signature

PoolInstance.isBusy()

Arguments

This method has no arguments.

Return

“True” if any object in the pool is busy (specifically if the onreadystate for any object is 1, 2 or 3), “false” if not (if the onreadystate for all objects is 0 or 4).

PoolInstance.queueLength()

Returns the number of calls currently queued. Currently running, in-progress calls are not represented. Note that this may differ from the number of requests as requests may be created with multiple calls.

Method Signature

PoolInstance.queueLength()

Arguments

This method has no arguments.

Return

Numeric. The number of calls outstanding in the pool’s queue.

PoolInstance.start()

Starts the pool’s polling interval if it has been manually stopped with the stop() method.

Method Signature

PoolInstance.start()

Arguments

This method has no arguments.

Return

Object, a reference to the current pool instance. This allows method chaining.

PoolInstance.stop()

Stops the pool’s polling interval. All currently running calls will complete but queued calls will not start. Also note that polling also disables call timeout checks.

Method Signature

PoolInstance.stop()

Arguments

This method has no arguments.

Return

Object, a reference to the current pool instance. This allows method chaining.

DP_AJAX Request

DP_AJAX Requests are generated using the DP_AJAX.createRequest() method.

Request Pool methods available:

Note arguments in square brackets are optional.

RequestInstance.abort()

Removes all queued calls related to the request from the queue and aborts all currently running calls. The ErrorHandler of aborted requests will be called if defined and the status of aborted calls will be “aborted”.

Method Signature

RequestInstance.abort()

Arguments

This method has no arguments.

Return

Boolean, true.

RequestInstance.addCall()

Adds a new call (HTTP request definition) to the request. Multiple calls can be added to the same request but none of them will be started until the request is added to an active request pool.

Method Signature

RequestInstance.addCall( [Method], [URL], [Parameters], [Headers], [Timeout], [MaxAttempts] )

Arguments

This method has six arguments:

  • Method: String, optional. Supports the following methods:
    • GET: Default. Call uses the GET method. Parameters are passed as URL variables.
    • POST: Call uses the POST method. Parameters are passed as form-field variables and content-type header is set as “application/x-www-form-urlencoded”.
    • SOAP: Call is to a SOAP 1.0 web service. Content-type header is set as “text/xml; charset=utf-8”.
    • SOAP12: Call is to a SOAP 1.2 web service. Content-type header is set as “application/soap+xml”.
  • URL: String or null, required. The URL to call. If URL is passed as an empty string (or is null) a null value will be added to the response (this is useful for forcing response positioning in multi-call requests).
  • Parameters: Object, optional. An object whose properties represent parameters to be passed with the request. Each property of the object will be passed as a name=value pair in the HTTP request.
  • Headers: Object, optional. An object whose properties represent additional HTTP Headers to be passed with the request. Each property of the object will be passed as a name=value pair in the HTTP header field.
  • Timeout: Number, Optional. Defaults to the value set in the associated request pool. The duration, in seconds, that represents the maximum time to attempt the request.
  • MaxAttempts: Number, Optional. Defaults to the value set in the associated request pool. The number of times that a request should be reattempted when errors are encountered. (In this case “failure” is considered an HTTP result code of something other than 200 or 0).

Return

Object, a reference to the current pool request instance. This allows method chaining.

Examples

DP_AJAX abstracts away much of the complexity of working with in-page HTTP requests. By consolidating requests into one or more request pools it manages resources better than creating ad hoc requests as needed and it eliminates the need to “chain” handlers or set up complex monitoring when multiple requests are required to perform some action.

Instantiating a Pool

The DP_AJAX.createPool() method is used to create request pools. The following will instantiate a basic request pool and assign a reference to the “myPool” variable:

myPool = DP_AJAX.createPool();

At this point the pool is created and ready to accept new requests.

Creating Requests

Requests are created using the DP_AJAX.createRequest() method and represent a container for related call(s) and the information needed to react to the response. You can define handlers (functions to call when the request completes) for both success and error conditions and additional arguments to pass to these handlers. Although handlers are optional (there are cases when the response doesn’t matter) they are nearly always used. An an example Let’s assume that:

  • The URL http://www.mysite.com/Add.htm, our service, accepts two numeric parameters (“FirstNum” and “SecondNum”), does some calculation on them and returns a single number as the result.
  • The client-side function AddUp(), our handler, accepts three numeric arguments and simply adds them up. The first argument to AddUp() is the output from our service and the second and third are calculated client-side before the service is called.

So, we want our request to first call the URL with the values “5” and “10” (which, let’s say, results in “15”) then pass the result along with the values “7” and “13” to the AddUp() handler function. The following code creates this request:

		// The handler function
	function AddUp(Num1, Num2, Num3) { alert(Num1 + Num2 + Num3) };

		// Create the pool
	myPool = DP_AJAX.createPool();

		// Create an array to hold the additional arguments needed by the handler
		// (Note that the first argument passed to the handler is always the results of the request.)
	HandlerArgs = new Array();
	HandlerArgs[0] = 7;
	HandlerArgs[1] = 13;

		// Create the request
	myRequest = DP_AJAX.createRequest(AddUp, HandlerArgs);

		// Create the Parameters to pass to the service URL (an object where each property will be passed as a parameter)
	ServiceParms = new Object();
	ServiceParms.FirstNum = 5;
	ServiceParms.SecondNum = 10;

		// Add the call to the request
	myRequest.addCall("GET", "http://www.mysite.com/Add.htm", ServiceParms);

		// Add the request to the pool
	myPool.addRequest(myRequest);
	

While the above code functions it’s verbose and a bit unwieldy. It cleans things up significantly to use literal notation as follows:

		// The handler function
	function AddUp(Num1, Num2, Num3) { alert(Num1 + Num2 + Num3) };

		// Create the pool
	myPool = DP_AJAX.createPool();

		// Create the request
	myRequest = DP_AJAX.createRequest(AddUp, {"FirstNum" : 5, "SecondNum" : 10});

		// Add the call to the request
	myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [7,13]);

		// Add the request to the pool
	myPool.addRequest(myRequest);
	

Finally you can also combine much of this into a single line with anonymous method calls and method chaining as follows:

		// The handler function
	function AddUp(Num1, Num2, Num3) { alert(Num1 + Num2 + Num3) };

		// Create the pool
	myPool = DP_AJAX.createPool();

		// Add the request to the pool
	myPool.addRequest(DP_AJAX.createRequest(AddUp, {"FirstNum" : 5, "SecondNum" : 10}).addCall("GET", "http://www.mysite.com/Add.htm", [7,13]));
	

The above three pieces of code are completely functionally identical. Breaking down the example we see that:

  • We’re calling http://www.mysite.com/Add.htm using the GET method.
  • We’ve generated an object (myParams in the first example) which contains property=value pairs. These will be converted to corresponding name=value parameters and passed to the service URL.
  • The function AddUp() is our handler. A reference to it (without the parenthesis as we’re passing a reference to the function itself, not the result of the function) is used as an argument DP_AJAX.createRequest(). When the request is completed this function will be called. The first argument of this call will be the results of the HTTP call in the form of: AddUp(HTTPResponseContent).
  • Arguments intended for the handler are added to an array (myArgs in the first example) and will be passed (unaltered and in the array-specified order) as additional arguments to the handler. In this case the values “7” and “13” will be passed as second and third arguments to the handler in the form of: AddUp(HTTPResponseContent, 7, 13).
  • The handler function adds up the three numbers and raises an alert with the total (in this case, if our math if correct, 35).

In this simple example the AddUp() function simply creates an alert with the total of the arguments. In reality the handler would most likely perform some action to either store or display the results within the current web page.

Remember that adding the request to the pool does not actually run the request. Instead it simply adds the request to the queue. Only after the request is run and completed will the handler be called. Don’t be confused and assume that the result of addRequest() will be the response from the HTTP request or the result returned from the handler. Code following addRequest() will run immediately; it will not wait for the response to complete.

Requests with Multiple Calls

One of the more powerful features of DP_AJAX is the ability to group multiple calls into a single request. There are three common ways this is accomplished:

  • Make the calls synchronously. This is perhaps the worst, but simplest option. Synchronous calls halt all processing (including interface updates) until the processing is complete effectively locking the application while they are running.
  • Chain handlers in such a way that one call’s handler creates the next call and only when they all are complete will the final handler be called with all of the data needed. It should be clear that this method impacts performance by essentially serializing the calls while adding significant complexity to the code.
  • Create some kind of monitoring (normally with a javascript interval) that checks the state of the calls and runs the actual handler only when all of the calls are completed. Obviously this adds complexity to the code and mixes data and management system code inelegantly.

Using DP_AJAX automates this process and only calls the data handler when the entire request – and all its associated calls – have completed. Working from the example above let’s assume that the input to AddUp() function comes from three distinct calls to the service. This might be coded as follows:

		// The handler function
	function AddUp(Nums) { alert(Nums[1] + Nums[2] + Nums[3]) };

		// Create the pool
	myPool = DP_AJAX.createPool();

		// Create the request
	myRequest = DP_AJAX.createRequest(AddUp);

		// Add the calls to the request
	myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [5,10]);
	myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [4,6]);
	myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [7,13]);

		// Add the request to the pool
	myPool.addRequest(myRequest);
	

Note that the handler has been changed to accept a single parameter, “nums” and reference it as an array. This is because the results of a multi-call request return the results as an array of values, one per call in the order they were added to the request. Also be aware that if the call results in an XML response then the value will be a native XML document rather than plain text.

Complex Responses

The default behavior of a request is to return just the data of a response (as XML or plain-text) either directly, in the case of a single call request, or as an array of simple values when there are multiple calls. However by setting the “SimpleResponses” argument of DP_AJAX.createRequest() to “false” much more information is returned. When active complex responses will be either a an object (for a single call request) or an array of objects (for multi-call requests). Each response object will have the following properties:

  • Status: The status of the completed HTTP call (for successful calls this will be “200”).
  • StatusText: Any text value associated with the HTTP status.
  • ResponseText: If available, the plain-text data returned by the HTTP call.
  • ResponseXML: If available, a platform-native XML document represented the data returned by the HTTP call.
  • Headers: An object whose property names/values represent the HTTP Header returned by the HTTP call.

Considering that, if “SimpleResponses” were false in our above examples our handler function would need to change accordingly:

		// The handler function
	function AddUp(Nums) { alert(Nums[1].ResponseText + Nums[2].ResponseText + Nums[3].ResponseText) };
	

The primary reason for enabling complex responses is to access the returned HTTP headers (a common need when accessing complex web services).

XML Convenience Methods

Although DP_AJAX will automatically return an appropriate XML document when needed the component provides several methods for creating and working with native XML documents. Full documentation for these methods is above, but in brief:

  • DP_AJAX.createXML(): Creates a blank XML document.
  • DP_AJAX.loadXML(): Creates a new document and loads it with data from a specified URL. (This is a very simplistic method however and it’s recommended you leverage a request pool for this task.)
  • DP_AJAX.parseXML(): Converts a plain-text representation of an XML packet and converts it to a native XML document.
  • DP_AJAX.xmlToString(): Converts an XML document to plain-text.

Revision History

June 8, 2013

  • Initial GITHUB release.

August 10, 2012

  • Initial Release

3 Comments

Add a Comment

Leave a Reply