Ajax: บันทึก trick เรื่องจาวาสคริปต์

 

ต้องการทำป้าย Loading ... แบบที่กูเกิลใช้
ทดลองแกะดู เขาใช้ css เป็นทำนองนี้ (แก้ไขและเปลี่ยนแปลงจากต้นฉบับแล้ว)

...
.hidden {
  display: none; 
}
#loading {
  position: absolute;
  top: 14em;
  height: 2em;
  left: 49%;
  z-index: 10000;
}
#loading p {
  padding: .5em 40px .5em 40px;
  text-align: center;
  line-height: 2em;
  color: #c66;
  background: #fee;
  border: solid 1px #c99;
}
...

เวลาใส่ในข้อความ html ก็ใช้ทำนองว่า...

...
<div id="loading" class="hidden"><p>Loading ... </p></div>
...

เวลาถูกเรียกใช้งานด้วยจาวาสคริปต์ โดยเมธอด POST
ก็ให้มาเปลี่ยนแปลง class จาก hidden เป็นคลาสอื่นตามต้องการ ด้วยคำสั่ง ...

document.getElementById("loading").className = "";

ก็จะแสดงผล Loading ... ออกมา
เวลางานเสร็จ ข้อมูลถูกส่งกลับมายัง client ก็ให้ตั้งคลาสกลับเป็น hidden ตามเดิม ด้วยคำสั่ง

document.getElementById("loading").className = "hidden";

ปัญหาคือจาวาสคริปต์รันโดยใช้แคช จึงข้ามลำดับขั้นตอนสลับไปหมด (ไม่แน่ใจนะครับ เดาเอาเฉย ๆ)
เลยต้องใช้การหน่วงเวลา โดยแบ่งการ Request ออกเป็นสองจังหวะ
ให้จังหวะแรกมาเรียกให้เลิก hidden ก่อน แล้วจึงเรียกให้ทำการ hidden ซ้ำอีกครั้ง

ได้ปรับให้โปรแกรมทำงานตามลำดับโดยเรียกใช้ฟังก์ชั่น setTimeout ในจังหวะแรก ดังนี้

<script>
function getXmlHttpRequestObject() {
  if (window.XMLHttpRequest) {
    return new XMLHttpRequest(); //Not IE
  } else {
    if(window.ActiveXObject) {
      return new ActiveXObject("Microsoft.XMLHTTP"); //IE
    } else {
      alert("Your browser doesn't support the XmlHttpRequest object. Better upgrade to Firefox.");
    } 
  }
}

var req = getXmlHttpRequestObject();

function d_post(cmd,argv) {
  arg1 = "cmd="+cmd+"/"+argv;
  req.open("POST", "?", false);
  req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  req.send(arg1);
  if (cmd=="info" || cmd=="source") {
    document.getElementById("loading").className = "";
    setTimeout("d_post('do_"+cmd+"','"+argv+"');", 1);
  
  } else if (cmd=="c2e" || cmd=="e2c") {
    document.getElementById("loading").className = "";
    setTimeout("d_post('do_"+cmd+"','"+char2url(argv)+"');", 1);

  } else if (cmd=="do_info" || cmd=="do_source" || cmd=="do_c2e" || cmd=="do_e2c") {
    document.getElementById("d_main").innerHTML = req.responseText;
    document.getElementById("loading").className = "hidden";
    document.getElementById("search_form").focus();
  }
}
  </script>

หลังจากใส่ฟังก์ชั่น setTimeout เข้าไป ปรากฎว่าโปรแกรมทำงานตามลำดับได้เรียบร้อย

มารู้ทีหลังว่า ภาษานี้เขาเขียนแบบไล่ฟังก์ชั่นเป็นทอด ๆ เพื่อให้การทำงานเป็นไปตามลำดับ
เขียนใหม่ได้เป็น

<script>
function getXmlHttpRequestObject() {
  if (window.XMLHttpRequest) {
    return new XMLHttpRequest(); //Not IE
  } else {
    if(window.ActiveXObject) {
      return new ActiveXObject("Microsoft.XMLHTTP"); //IE
    } else {
      alert("Your browser doesn't support the XmlHttpRequest object. Better upgrade to Firefox.");
    } 
  }
}

var req = getXmlHttpRequestObject();

function d_post(cmd,argv) {
  document.getElementById("loading").className = "";
  setTimeout("xd_post('" + cmd + "','" + argv + "');", 1);
}

function xd_post(cmd,argv) {
  arg1 = "cmd="+cmd+"/"+argv;
  req.open("POST", "?", false);
  req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  req.send(arg1);
  if (cmd=="info" || cmd=="source" || cmd=="c2e" || cmd=="e2c") {
    document.getElementById("d_main").innerHTML = req.responseText;
    document.getElementById("loading").className = "hidden";
  }
}    
</script>