All,
I am studying Ajax using the Head First Ajax book. In the first chapter they give some code example which I simplified a bit. I added a bunch of alert
to understand what was happening. Here is the code:
HTML + Ajax (index.php
):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Rob's Rock 'n' Roll Memorabilia</title>
<link rel="stylesheet" href="css/default.css" />
<script>
function createRequest() {
try {
request = new XMLHttpRequest();
} catch (tryMS) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (otherMS) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = null;
}
}
}
return request;
}
function getDetails(img){
var title = img.title;
alert("getDetails1");
request = createRequest();
alert("getDetails2");
if (request == null) {
alert("Unable to create request");
return;
}
var url= "getDetails.php?ImageID=" + escape(title);
alert("getDetails3");
request.open("GET", url, true);
alert("getDetails4");
request.onreadystatechange = displayDetails;
alert("getDetails5");
request.send(null);
alert("getDetails6");
}
function displayDetails() {
alert("displayDetails1");
if (request.readyState == 4) {
alert("Request.readyState is 4");
if (request.status == 200) {
alert("Request.status is 200");
detailDiv = document.getElementById("description");
alert("displayDetails2");
detailDiv.innerHTML = request.responseText;
alert("displayDetails3");
}else{
alert("Request.status not 200");
return;
}
}else{
alert("Request.readystate not 4");
return;
}
}
</script>
</head>
<body>
<div id="wrapper">
<div id="thumbnailPane">
<img src="images/SISL_Avatar2.JPG"
title="SISL" id="SISL" onclick="getNextImage()" />
<img src="images/itemGuitar.jpg" width="301" height="105" alt="guitar"
title="itemGuitar" id="itemGuitar" onclick="getDetails(this)"/>
<img src="images/itemShades.jpg" alt="sunglasses" width="301" height="88"
title="itemShades" id="itemShades" onclick="getDetails(this)" />
<img src="images/itemCowbell.jpg" alt="cowbell" width="301" height="126"
title="itemCowbell" id="itemCowbell" onclick="getDetails(this)" />
<img src="images/itemHat.jpg" alt="hat" width="300" height="152"
title="itemHat" id="itemHat" onclick="getDetails(this)" />
</div>
<div id="detailsPane">
<img src="images/blank-detail.jpg" width="346" height="153" id="itemDetail" />
<div id="description"></div>
</div>
</div>
</body>
</html>
<?php
$details = array (
'itemGuitar' => "<p>Pete Townshend once played this guitar while his own axe was in the shop having bits of drumkit removed from it.</p>",
'itemShades' => "<p>Yoko Ono's sunglasses. While perhaps not valued much by Beatles fans, this pair is rumored to have been licked by John Lennon.</p>",
'itemCowbell' => "<p>Remember the famous \"more cowbell\" skit from Saturday Night Live? Well, this is the actual cowbell.</p>",
'itemHat' => "<p>Michael Jackson's hat, as worn in the \"Billie Jean\" video. Not really rock memorabilia, but it smells better than Slash's tophat.</p>"
);
if (isset($_REQUEST['ImageID'])){echo $details[$_REQUEST['ImageID']];}
?>
Here is the URL that is called by Ajax (getDetails.php
):
<?php
$details = array (
'itemGuitar' => "<p>Pete Townshend once played this guitar while his own axe was in the shop having bits of drumkit removed from it.</p>",
'itemShades' => "<p>Yoko Ono's sunglasses. While perhaps not valued much by Beatles fans, this pair is rumored to have been licked by John Lennon.</p>",
'itemCowbell' => "<p>Remember the famous \"more cowbell\" skit from Saturday Night Live? Well, this is the actual cowbell.</p>",
'itemHat' => "<p>Michael Jackson's hat, as worn in the \"Billie Jean\" video. Not really rock memorabilia, but it smells better than Slash's tophat.</p>"
);
echo $details[$_REQUEST['ImageID']];
?>
The question: Why does the function displayDetails
run twice at readystate 4?
When I run the above, the code seems to run through the displayDetails()
function twice. I first get the displayDetails1
alert signaling I've entered the function. I then get the alerts related to the readyState
not being 4, then not being 4 again, then being 4 (Request.readyState is 4
). Then the status alert tells me the status is 200. Up to now, nothing unexpected.
After that I get something weird. I get the displayDetails2
alert, then the page is modified according to the function and I get the displayDetails3
alert. I then expect to exit the function. Instead I get again the displayDetails1
, Request.readyState is 4
(a second time!), Request.status is 200
, displayDetails2
, and displayDetails3
alerts, as if the entire function had run a second time. Why is that?
PS:
1) After the 2nd round, I then get the getDetails6
alert I expect.
2) The page functions as it should - from a user's standpoint there's nothing unusual if the alerts are disabled.
3) I am developing locally on WampServer, on a WinXP machine (I know...).
4) If I add:
function alert(msg) {
console.log(msg);
}
to my script the log only registers one readyState is 4
...
RESOLUTION
I have done 3 tests:
1 - with the alerts only, I get two readyState is 4
alerts.
2 - if I log the alerts, the log only shows one readyState is 4
alert.
3 - if I both log and display the alert pop-ups (using this function), I get two readyState is 4
alerts (and the log shows that).
My take on this is that it is the alerts themselves that cause a script execution delay and cause the function to effectively run twice.
The javascript alert
is blocking your UI thread, probably long enough for your browser to finish loading the AJAX request. Since you don't check the request.readyState
until after the alert, it can be updated by the browser before you check it.
Try modifying your event handler:
function displayDetails() {
var rs = request.readyState;
alert("displayDetails1");
if (rs == 4) {
alert("Request.readyState is 4");
//rest of code...
You will see just one alert of "Request.readyState is 4"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With