AJAX Long Polling

 

Long Polling เป็นเทคนิคการเขียน ajax ที่ทำให้ ajax ดู real-time ขึ้น. ในขณะที่การเขียนแบบทั่วไป ajax จะ request/response มาทุกๆ x วินาที (กรณีเป็น chat )แม้ว่าจะไม่มีข้อมูลอัพเดทก็ตาม แต่ Long Polling จะไม่ response กลับมาถ้าหากไม่มีข้อมูลอัพเดท(หรือ ถึงเวลาที่กำหนด) ซึ่ง server จะหน่วงค้างไว้จนกระทั่งมีข้อมูลอัพเดท หรือถึงเวลาที่กำหนด ทำให้ Long Polling ดูเหมือนตอบสนองได้ไวกว่า

Simple Long Polling (Server)

การเขียน Long Polling (server) สามารถทำได้ง่ายๆ แค่การหน่วง server ไม่ให้จบสคริปในทันที แต่จะรัน(กึ่ง)infinity loop ไปเรื่อยๆ โดยมีการ sleep(หรือ usleep) ไว้ทุกรอบ loop เพื่อไม่ให้ CPU usage เพิ่มขึ้นมากนัก
* ถ้าหากไม่มีการ sleep เราจะไม่สามารถคุมความเร็วของลูปได้ (ลูปจะวิ่งตามความเร็ว CPU เต็มสปีด) แต่หากใช้ sleep(1) อย่างน้อยเราก็มั่นใจได้ว่า 1 วินาที ลูป 1 รอบ (แทนที่จะเป็น 100,1000 รอบ ซึ่งไม่ดีแน่)

< ?
/**
 * Simple long Polling
 * @author ExpertDuck
 **/
error_reporting(E_ALL);
define('HOLD_TIME',30);
set_time_limit(HOLD_TIME+1);//set time_limit ใหม่ ไม่ให้หมดเวลาก่อนระยะเวลาที่ hold ไว้
$expire = time()+HOLD_TIME; //ค้างไว้ 30 วิ
do{
   //ตรงนี้ก็ดึงข้อมูลมาปกติ
   $data = get_data();
   if(!empty($data))
     break; //break loop
   sleep(1);
}while($expire < time());

if(empty($data))
  echo json_encode($data);
else
  echo json_encode(array('noop' => true));

ส่วนของ Client (javascript) ก็เขียนให้ request ทันที(หรือหน่วงไว้สั้นๆ 1 วิ) แล้วไปหน่วงต่อที่ server แทน ทำให้สามารถรับข้อมูลมาได้ทันที

/**
 * Long Polling Client
 * @author ExpertDuck
 **/
 
//$ = jQuery;
$(function(){
	var parseData = (function(json){
		//ทำอะไรกับ ข้อมูลหละ....
		
	});
	var req = (function(){
		$.ajax({
			'url':'ajax.php',
			'dataType':'json',
			'success':function(json){
				if(json.noop)
				{
					//ถ้า response noop มา ให้หน่วงไว้ 1 วิ
					setTimeout(function(){
						req();
					},1000);
				}else{
					parseData(json);
					req();
				}
			},
			'error':console.log // หาก error ส่งไป console.log(Firebug)
		});
	});
	
});

การใช้งานจริง

ในการใช้งานจริงจะต้อง optimize code การเล็กน้อยครับ

Ghost Process
กรณีที่ user กดปิดหน้าต่างหรือคลิ๊กไปที่อื่น ในขณะที่ ajax ยังวิ่งค้างอยู่ จะทำให้เกิด ghost process ที่ php ( php ยังรันอยู่) จนกว่าจะถึงเวลาที่กำหนด (30 วิในตัวอย่าง)
การเขียนใช้จริงส่วนของ php จะต้อง flush(); ข้อมูลออกทุกๆลูป เพิ่อให้ php ตรวจสอบ connection ได้ป้องกันการเกิด ghost process ถ้าเกิดว่า client disconnect ขึ้นมาในช่วงนั้น php ก็สามารถจบสคริป ได้ทันที

<?
//...
do{
   $data = get_data();
   if(!empty($data))
     break; //break loop

   //ป้องกัน Ghost Process
   echo "\n";
   flush();
   //-----------------

   sleep(1);
}while($expire < time());
//...

Check Update
อีกส่วนคือการตรวจสอบข้อมูลอัพเดท ถ้าหากต่อ db การใช้ SELECT * FROM my_table WHERE xxx ดูจะไม่เหมาะกับ Long Polling ซะเท่าไหร่ ถ้าเอาไปใช้ใน Loop
การแก้ไขส่วนนี้เพื่อลดการใช้ทรัพยากรณ์ลด ให้เก็บตัวแปร updated ไว้ที่อื่น(อาจจะ table_option หรือไว้ในไฟล์แทน) ตอบอัพเดทก็ให้ไป update ส่วนนั้นด้วย
ตัวอย่างเช่น

//update.php
//....update ข้อมูลปกติ
//แล้วตามด้วย
file_put_contents('updated.txt',time());

//long-polling.php
//...ขอข้ามไปส่วน get_data
function get_data()
{
  $time = file_get_contents('updated.txt');
  if($time< =time())return false;

  //... get_data ปกติ
}

สุดท้าย
สุดท้ายแล้วดูเหมือนว่า Long-Polling จะเหมาะที่จะใช้ ShoutBox/Chat มากที่สุดเพราะการอัพเดทข้อมูลที่ค่อนข้างจะบ่อย และต้องการการตอบสนองที่ทันที แต่หากเอาไปใช้งานในลักษณะอื่นดูจะไม่ค่อยเหมาะสมเท่าที่ควร เพราะจะทำให้การเขียนสคริปเหมือนจะยุ่งยากขึ้น

ปล.อ่านๆแล้วงงๆยังไงก็ไม่รู้เนอะ ฮ่าๆ ไม่รู้จะอธิบายยังไงดีครับ ก็ขอโทษละกันครับ

จบ…

 

แสดงความคิดเห็น