views:

76

answers:

1

Alright, I'm trying to make an AJAX Chat system that polls the chat database every 400ms. That part is working, the part of which isn't is the Active User List. When I try to combine the two requests, the first two requests are made, then the whole thing snowballs and the usually timed (12 second) Active User List request starts updating every 1ms and the first request NEVER happens again. Displayed is the entire AJAX code for both requests:

var waittime=400;chatmsg=document.getElementById("chatmsg");
room = document.getElementById("roomid").value; 
chatmsg.focus()
document.getElementById("chatwindow").innerHTML = "loading...";
document.getElementById("userwindow").innerHTML = "Loading User List...";
var xmlhttp = false;
var xmlhttp2 = false;
var xmlhttp3 = false;
function ajax_read(url) {
if(window.XMLHttpRequest){
    xmlhttp=new XMLHttpRequest();
    if(xmlhttp.overrideMimeType){
        xmlhttp.overrideMimeType('text/xml');
    }
} else if(window.ActiveXObject){
    try{
        xmlhttp=new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
        try{
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        } catch(e){
        }
    }
}
if(!xmlhttp) {
    alert('Giving up :( Cannot create an XMLHTTP instance');
    return false;
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState==4) {
    document.getElementById("chatwindow").innerHTML = xmlhttp.responseText;
    setTimeout("ajax_read('methods.php?method=r&room=" + room +"')", waittime);
    }
}
xmlhttp.open('GET',url,true);
xmlhttp.send(null);
}
function user_read(url) {
if(window.XMLHttpRequest){
    xmlhttp3=new XMLHttpRequest();
    if(xmlhttp3.overrideMimeType){
        xmlhttp3.overrideMimeType('text/xml');
    }
} else if(window.ActiveXObject){
    try{
        xmlhttp3=new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
        try{
            xmlhttp3=new ActiveXObject("Microsoft.XMLHTTP");
        } catch(e){
        }
    }
}
if(!xmlhttp3) {
    alert('Giving up :( Cannot create an XMLHTTP instance');
    return false;
}
xmlhttp3.onreadystatechange = function() {
if (xmlhttp3.readyState==4) {
    document.getElementById("userwindow").innerHTML = xmlhttp3.responseText;
    setTimeout("ajax_read('methods.php?method=u&room=" + room +"')", 12000);
    }
}
xmlhttp3.open('GET',url,true);
xmlhttp3.send(null);
}
function ajax_write(url){
if(window.XMLHttpRequest){
    xmlhttp2=new XMLHttpRequest();
    if(xmlhttp2.overrideMimeType){
        xmlhttp2.overrideMimeType('text/xml');
    }
} else if(window.ActiveXObject){
    try{
        xmlhttp2=new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
        try{
            xmlhttp2=new ActiveXObject("Microsoft.XMLHTTP");
        } catch(e){
        }
    }
}
if(!xmlhttp2) {
    alert('Giving up :( Cannot create an XMLHTTP instance');
    return false;
}
xmlhttp2.open('GET',url,true);
xmlhttp2.send(null);
}
function submit_msg(){
nick = document.getElementById("chatnick").value;
msg = document.getElementById("chatmsg").value;
document.getElementById("chatmsg").value = "";
ajax_write("methods.php?method=w&m=" + msg + "&n=" + nick + "&room=" + room + "");
}
function keyup(arg1) { 
if (arg1 == 13) submit_msg(); 
}
var intUpdate = setTimeout("ajax_read('methods.php')", waittime);
var intUpdate = setTimeout("user_read('methods.php')", waittime);
+1  A: 

The problem is that in user_read a timer is set up that runs ajax_read after 12 s, with the correct URL. So, when this ajax_read is called, it fetches information and sets up a new timeout, this time calling ajax_read after waittime, with ?method=r…. So after the first timeout of user_read, it is never called again.

FYI, I watched this with (the Net panel of) Firebug and a bogus form and methods.php on a local web server. It became clear after setting waittime to 4000 and using .innerHTML += …, resulting in two calls every 4 seconds.

index.html (I know, it's quick'n'dirty):

<!DOCTYPE html>
<html>
 <head>
  <meta charset=UTF-8>
  <title>Chat</title>
 </head>
 <body>
  <input id="chatnick" type="text" value="Nickname"><br>
  <input id="roomid" type="text" value="4"><br>
  <input id="chatmsg" type="text"><br>
  <div id="userwindow" style="width: 500px; height: 300px"></div><br>
  <div id="chatwindow" style="width: 300px; height: 300px"></div><br>
  <script src="js.js"></script>
 </body>
</html>

bogus methods.php:

blah<br>

Also be aware of the possibility that xmlhttp.status might not be 200.

Marcel Korpel
So how would this be fixed, I can see where renaming the user_read call to user_read (instead of ajax_read), but was this the only issue, meaning that this was the only reason it was snowballing?
Nik
@Nik – When I corrected that function call and put `waittime` back to 400, everything seemed to run fine *using a local web server*. I don't know what happens in a real-world situation of a slower connection, with so many requests, but I don't want to put that much load on my own company's server. BTW, I think you can re-factor your code a bit: passing a string instead of a function reference to `setTimeout` is not a good idea (way slower and mostly unnecessary) and having that XMLHttpRequest code three times is not efficient, either.
Marcel Korpel
@Marcel, I'm not too sure how to consolidate the requests, and I don't understand where you say that I shouldn't pass a string, because the reference to setTimeout is a function (ajax_chat(url)).
Nik
@Nik – Just create the files in my answer and you're able to test this, e.g. using [Firebug](http://getfirebug.com/). And you're actually passing strings to setTimeout, e.g. `"ajax_read('methods.php?method=r`. This way, you can't pass arguments to ajax_read, so you should find another way of achieving what you want. It's way more efficient. BTW, you do check if those variables sent to the server (like `msg` and `room`) don't contain malicious code, don't you?
Marcel Korpel
Yes, the PHP file checks, escapes, and validates each variable when it's received, then terminates the request if it finds anything it doesn't like. Would I just set xmlhttp.open to the url which contains the strings?
Nik
@Nik – You mean in terms of security? I think you can. Just remember that the maximum length of a URL in IE is about 2083, so there are limits in the amount of data that can be send via a GET request.
Marcel Korpel
Would it work as if I set it via setTimeout?
Nik
@Nik – You mean inside of the `setTimeout` function? Yeah, I don't know a reason why it shouldn't.
Marcel Korpel
So why is it less secure as if I set it via setTimeout rather than xmlhttp.open?
Nik
@Nik – Oh, you mean the string that you pass to `setTimeout`? That string actually gets `eval` uated, so you risk that someone injects malicious (JavaScript) code via one of those variables you add to that string. E.g., if the user can manipulate `room`, (s)he can close the function and do something mean by setting that variable to `'); /* evil code here */`.
Marcel Korpel
Alright, thanks. I'm not an expert in JS.
Nik
How would I consolidate the requests so it doesn't place a large load?
Nik
@Nik – What do you mean by ‘a large load’?
Marcel Korpel
You said "I don't want to put that much load on my own company's server."
Nik
@Nik – Ah, now I understand. I meant: firing that much HTTP requests on it. Though they should be able to handle it, I don't want to test it.
Marcel Korpel