How to call asynchronously web servers with Javascript ?

Problem :

We wanted to display or hide information from more than five web servers when loading a homepage. Instead of waiting until all the servers reply to us ( synchronous method) the customer wanted to see the information as soon as the server would reply. This solution presents a better user experience because the webpage is more responsive.

Solution

I will decompose the solution in several parts and explain each steps

  • A HTML/W3.CSS webpage with a button calling the javascript method
  • The Javascript code calling multiple web servers
  • The Javascript class that call a web server
  • The callback method which handle the response of the web server
  • The Javascript function which updates the webpage after obtaining a response from the server.

HTML web page

The html webpage contains a button and a text input. The text input is sent to the web servers when we click the button.

main_webpage
This is a simple example of webpage

The link to my javascript file :

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

When we click on the button we call a javascript function which will use the text content of the input “myinput”.

 <input name="myinput" id="myinput" class="w3-input w3-border w3-light-grey" type="text">
<button class="w3-btn w3-blue-grey" onclick="callWeb()">Load Web Servers</button>

callWeb() is a Javascript function which will retrieve the input value and call web servers.

function callWeb() {
    var input = document.getElementById('myinput'),
       myinput = input.value;
    if (myinput) {
       loadWebServers(input);
    } else {
       alert('Please enter an input!');
       input.focus();
    }
}

To avoid the error “The character encoding of the HTML document was not declared” : I have added these lines in the HTML :

<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">

For information in this example I use W3.CSS for the style. It is a modern CSS framework with built-in responsiveness. It is an equivalent of Bootstrap. More information at https://www.w3schools.com/w3css/.

Javascript : Calling multiple web servers

I will present the javascript function which send the request and the callback function which handle the response .

function loadWebServers(input)
{
    var value1 = input
    var value2 = ''
    var value3 = ''
    loadWebABC(value1);
    loadWebX(value1);
}

In this example we call only two web servers. loadWebABC call a web service with XML request. loadWebX call another web service with a JSON request.

function loadWebABC(value1)
{
 updateLoading();
MyClassRequest.sendXmlRequest("http://example.com/service", "myinput=”+ value1, "callbackWebABC");
}

When the server replies, the callback will handle the response :

function callbackWebABC(xml)
{
    updateLoading();
    var rootInfo = xml.getElementsByTagName("root-info");
    //parse more information
   infoextracted=…..
    showOrDisplayInfo(infoextracted);
}

Javascript : Detail of the class that call the web server

XmlHttpRequest is the class used to call distant web servers.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

If you use XMLHttpRequest from an extension, you should use it asynchronously. In this case, you receive a callback when the data has been received, which lets the browser continue to work as normal while your request is being handled.

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests

MyClassRequest is the equivalent of a class in Javascript world. It is defined in a file called request.js :

var MyClassRequest = {
	loading : false,

updaters : new Array(),

	Updater : function(request, backFunction, param, isXml, isJson) {
		this.request = request;
		this.backFunction = backFunction;
		this.param = param;
		this.isXml = isXml;
		this.cancelled = false;
		this.isJson = isJson;
	},

	createRequest : function() {
		var request = false;
		try {
			request = new XMLHttpRequest();
		} catch (trymicrosoft) {
			try {
				request = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (othermicrosoft) {
				try {
					request = new ActiveXObject("Microsoft.XMLHTTP");
				} catch (failed) {
					request = false;
				}
			}
		}
		return request;
	},

	sendXmlRequest : function(url, urlParam, backFunction, param) {
		return this
				.sendRequest(url, urlParam, backFunction, param, true, false);
	},

	sendRequest : function(url, urlParam, backFunction, param, isXml, isJson, timeout) {
		 if (typeof(timeout)==='undefined') {
			 timeout = 0;
		 }
		var request = this.createRequest();

		if (!request) {
			alert("Request not supported");
			return -1;
		} else {
			var index = this.updaters.length;
			this.updaters[index] = new MyClassRequest.Updater(request,
					backFunction, param, isXml, isJson);

			request.open("POST", url, true);
			request.onreadystatechange = MyClassRequest.receiveRequest;
			if (timeout != null && timeout > 0) {
				request.timeout = timeout;
				request.ontimeout = MyClassRequest.timeoutRequest;
			}
			request.setRequestHeader("Content-Type",
					"application/x-www-form-urlencoded; charset=UTF-8");
			request.send(urlParam);

			this.setLoading("true");
			return index;
		}
	},

As you can see the function sendXmlRequest is a sub function of sendRequest. sendRequest will use the object XMLHttpRequest or an equivalent for microsoft supported browser. This important part in this function is :

request.onreadystatechange = MyClassRequest.receiveRequest;

It is receiveRequest function which will trigger the callback function defined previously.

receiveRequest : function() {
		var stillLoading = false;
		for ( var i = MyClassRequest.updaters.length - 1; i >= 0; i--) {
			var updater = MyClassRequest.updaters[i];
			if (updater != null) {
				if (updater.request.readyState == 4) {
					MyClassRequest.updaters[i] = null;
					if (updater.cancelled == false) {
						if (!updater.request.status == 200) {
							alert("No response from server");
						} else {
                                                        if (updater.backFunction) {
							callbackFunction(updater);
                                                        }
						}
					}
				} else {
					stillLoading = true;
				}
			}
			MyClassRequest.setLoading(stillLoading);
		}
	},

callbackFunction is the function which will actually call our callback function when we receive correctly a response form the distant web server.

function callbackFunction(updater)
{

var func = new Function("response", "param",
			updater.backFunction
					+ "(response, param)");
	if (updater.isXml) {
		var xml = updater.request.responseXML;
		if (MyClassRequest.checkErrors(xml)) {
			func(false, updater.param);
		} else {
			func(xml, updater.param);
		}
	} else {
		func(updater.request.responseText,
				updater.param);
	}

}

Javascript : update the webpage

In the previous callback method we use a function showOrDisplayInfo(). This function will display or hide element in the web page. This is a simplified version of the function but as you can see it modifies an HTML element to show or hide this element.

function showOrDisplayInfo(infoextracted) {
for (var infoin infoextracted)
    {
      var idElementToShow ="elementX"+ infoin;
         show( idElementToShow );
    }
}

function show(element)
{
  if (element)
  {
    element.style.display="";
  }
}

function hide(element)
{
  if (element)
  {
    element.style.display="none";
  }
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s