使用异步xmlhttp请求的回调函数问题

时间:2013-06-27 09:28:00

标签: javascript asynchronous xmlhttprequest

更新

我修改了Bamar建议的代码。我现在使用实例变量来保存回调函数。但是,问题仍然存在,每个makeRequest()调用都使用相同的回调函数。


我在JavaScript中创建了一个http客户端,它适用于同步GET和POST调用,但如果我使用具有两个或更多回调函数的异步请求,则会为每个请求调用相同的函数。

Service.aspx文件只是中继参数名称的值,因此应该针对每个请求进行更改。

以下是JavaScript代码:

//-- 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;
        }
    }

以下是我如何使用客户端(异步):

<!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>

2 个答案:

答案 0 :(得分:1)

您需要为每个并发的AJAX调用使用单独的httpClient对象。

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();

httpClient类中,您需要使回调函数成为实例变量,而不是全局变量,因此$_callbackFunction的所有使用都应为this.$_callbackFunction

答案 1 :(得分:0)

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

请注意此处的XSS,以防未正确转发响应。 最好使用document.createElement()和document.createTextNode()。