0

Update

I have modified the code as Bamar suggested. im now using a instance variable to hold the callback function. However, the problem remains the same, the same callback function is used for each makeRequest() call.


I have made a http client in JavaScript, its working fine for synchronous GET and POST calls, but if i use asynchronous requests with two or more callback functions, then the same function gets called for each request.

The Service.aspx file just relays the value of the parameter name, so that should change for each request.

Here is the JavaScript code:

//-- Usage examples ----------------------------------------------
/*
    //Full
    client = new httpClient();
    client.method("get");
    client.baseUrl("Service.aspx");
    client.requestData({name: "John", age: 56, location: "Kansas City"});
    var response = client.makeRequest();
    alert(response);

    //Multiple requests
    client = new httpClient();
    client.baseUrl("Service.aspx");

    client.requestData("?q=foo");
    var data = client.makeRequest();
    alert(data);

    client.requestData("?q=foobar");
    var data = client.makeRequest();
    alert(data);

    //Minimal
    client = new httpClient();
    client.baseUrl("Service.aspx?q=test");
    client.makeRequest();

    //Minimal, with deafult base URL http://localhost/
    client = new httpClient();
    client.requestData("?q=foobar");
    client.makeRequest();

    //Full, with response output contained in an object
    client = new httpClient();
    client.method("get");
    client.baseUrl("Service.aspx");
    client.requestData("?q=test");
    var requestObject = client.makeRequestObject();
    alert(requestObject.MimeType);
    alert(requestObject.charset);

    //Custom callback function to handle asychronous httprequests
    myCallback = function (response) {
        document.getElementById("div").innerHTML += response;
    }

    client = new httpClient();

    client.asynchronous(true);
    client.method("get");
    client.baseUrl("Service.aspx");
    client.callback(myCallback);

    client.requestData({ name: "Peter", age: 45, location: "Kansas City" });
    client.makeRequest();

    */

    function httpClient() {
        this.$baseUrl = "http://localhost/";
        this.$method = "get";
        this.$requestData = "";
        this.$asynchronous = false;
        this.$callbackFunction = "";
        this.$invokeCallback = function (func, response) {
            func(response);
        }
    }

    httpClient.prototype.method = function (requestMethod) {
        this.$method = requestMethod;
    }

    httpClient.prototype.baseUrl = function (requestBaseUrl) {
        this.$baseUrl = requestBaseUrl;
    }

    $_xmlhttpConstruct = function () {
        var xmlhttp;
        if (window.XMLHttpRequest) {//IE7+, Firefox, Chrome, Opera, Safari
            return new XMLHttpRequest();
        }
        else {//IE6, IE5
            try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
            catch (e) { }
            try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
            catch (e) { }
            try { return new ActiveXObject("Microsoft.XMLHTTP"); }
            catch (e) { }
        }
    }

    httpClient.prototype.setRequestHeader = function (header, value) {

    }

    httpClient.prototype.callback = function (func) {
        this.$callbackFunction = func; //Does not get set to new callback function on multiple requests

    }

    httpClient.prototype.asynchronous = function (boolean) {
        this.$asynchronous = boolean;
    }

    httpClient.prototype.makeRequest = function () {

        //Initializing the xmlhttp object
        var xmlhttp = $_xmlhttpConstruct();

        if (this.$requestData == undefined) {
            xmlhttp.open(this.$method, this.$baseUrl, this.$asynchronous);
        }
        else {
            if (this.$method == "post") {

                xmlhttp.open(this.$method, this.$baseUrl, this.$asynchronous);
                xmlhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                xmlhttp.setRequestHeader("Cache-Control", "no-cache, must-revalidate"); //HTTP 1.1
                //xmlhttp.setRequestHeader("Pragma", "no-cache"); //HTTP 1.0
                //xmlhttp.setRequestHeader("Expires", "Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past

                xmlhttp.send(this.$requestData);

                invokeCallback = this.$invokeCallback;
                callbackFunction = this.$callbackFunction;

                if (this.$asynchronous) {
                    xmlhttp.onreadystatechange = function () {
                        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                            //Callback
                            invokeCallback(callbackFunction, xmlhttp.responseText);
                        }
                    }
                }
                else {
                    return xmlhttp.responseText;
                }

                //alert("URL: " + this.$baseUrl + "\n" + "Method: " + this.$method + "\n" + "Request data: " + this.$requestData);
            }

            if (this.$method == "get") {

                xmlhttp.open(this.$method, this.$baseUrl + this.$requestData, this.$asynchronous);
                xmlhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                xmlhttp.setRequestHeader("Cache-Control", "no-cache, must-revalidate"); //HTTP 1.1
                //xmlhttp.setRequestHeader("Pragma", "no-cache"); //HTTP 1.0
                //xmlhttp.setRequestHeader("Expires", Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
                xmlhttp.send(null);

                invokeCallback = this.$invokeCallback;
                callbackFunction = this.$callbackFunction;

                if (this.$asynchronous) {
                    xmlhttp.onreadystatechange = function () {
                        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                            //Callback
                            invokeCallback(callbackFunction, xmlhttp.responseText);
                        }
                    }
                }
                else {
                    return xmlhttp.responseText;
                }

                //alert("URL: " + this.$baseUrl + "\n" + "Full request URL: " + this.$baseUrl + this.$requestData + "\n" + "Method: " + this.$method + "\n" + "Request data: " + this.$requestData);
            }
        }
    }

    httpClient.prototype.requestData = function (data) {

        this.$requestData = "";

        if (typeof (data) == "object") {
            var i = 0;
            for (key in data) {
                if (i == 0) {
                    if (this.$method == "get") {
                        this.$requestData += "?" + key + "=" + data[key];
                    }
                    if (this.$method == "post") {
                        this.$requestData += key + "=" + data[key];
                    }
                    i++;
                }
                else {
                    this.$requestData += "&" + key + "=" + data[key];
                }
            }
        }
        else {
            this.$requestData = data;
        }
    }

Here is how i use the client (asynchronous):

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script type="text/javascript" src="httpClient.js"></script>
</head>
<body>
<form id="form1">

<div id="debug"></div>

</form>
<script type="text/javascript">
    //Custom callback functions to handle asychronous httprequests
    function testone(response) {

        document.getElementById("debug").innerHTML += "<div style='color: green;'>" + response + "</div>";
    }
    function testtwo(response) {

        document.getElementById("debug").innerHTML += "<div style='color: red;'>" + response + "</div>";
    }

    clientOne = new httpClient();

    clientOne.asynchronous(true);
    clientOne.method("get");
    clientOne.baseUrl("Service.aspx");

    clientOne.callback(testone);

    clientOne.requestData({ name: "Peter", age: 45, location: "Kansas City" });
    clientOne.makeRequest();

    //---------------------------------------------------

    clientTwo = new httpClient();

    clientTwo.asynchronous(true);
    clientTwo.method("get");
    clientTwo.baseUrl("Service.aspx");

    clientTwo.callback(testtwo);

    clientTwo.requestData({ name: "Mary", age: 45, location: "Kansas City" });
    clientTwo.makeRequest();


    //Synchronous works!
    /*
    client = new httpClient();

    client.asynchronous(false);
    client.method("get");
    client.baseUrl("Service.aspx");

    client.requestData({ name: "Peter", age: 45, location: "Kansas City" });
    testone(client.makeRequest());

    client.requestData({ name: "Mary", age: 45, location: "Kansas City" });
    testtwo(client.makeRequest());
    */

    </script>
</body>
</html>
1
  • A client can only have one callback function. You need to create distinct clients for each AJAX call. Commented Jun 27, 2013 at 9:56

2 Answers 2

1

You need to use a separate httpClient object for each concurrent AJAX call.

client1 = new httpClient();

client1.asynchronous(true);
client1.method("get");
client1.baseUrl("Service.aspx");

client1.callback(testone);

client1.requestData({ name: "Peter", age: 45, location: "Kansas City" });
client1.makeRequest();

client2 = new httpClient();

client2.asynchronous(true);
client2.method("get");
client2.baseUrl("Service.aspx");

client2.callback(testtwo);

client2.requestData({ name: "Mary", age: 45, location: "Kansas City" });
client2.makeRequest();

And in your httpClient class, you need to make the callback function an instance variable, not a global variable, so all uses of $_callbackFunction should be this.$_callbackFunction.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your answer Barmar, i have updated my question, however when i use two seperate instances of httpClient the result is the same, only testtwo() is used. You state that "You need to use a separate httpClient object for each concurrent AJAX call." is this based on my code or how the xmlhttp object works?
It's based on how the xmlhttp object works. An object can only have one callback at a time.
Okay, then i guess that creating two seperate instances of httpClient should fix the problem, however it does not work, only testtwo() is invoked, would you mind looking through my code, maby you can spot the problem. i have been looking at this for hours now. :)
I updared the answer: the problem is that you only have one $_callbackFunction variable, it needs to be per-object.
I'm unsure if this is being maintained properly when $_invokeCallback is called. This is getting a bit out of my area of Javascript expertise. I normally use jQuery, it takes care of all this.
0
document.getElementById("debug").innerHTML += "<div style='color: green;'>" + response + "</div>";

Watch out for the XSS here in case response is not properly escaped. Better to use document.createElement() and document.createTextNode().

1 Comment

Thanks, this is just for test/debug purposes though. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.