Tag Archive เอแจ็ค

Byphunsanit

jQuery: Ajax รับข้อมูลแบบ stream

บางงานต้องใช้เวลาในการทำงาน ถ้าปล่อยให้ user รออย่างเดียวก็จะกังวลว่ามันจะทำงานสำเร็จหรือมี error รึเปล่า เคยเขียนวิธี jQuery Ajax แบบอนุกรมตามลำดับ ไว้ แต่อาจจะไม่เหมาะถ้า task บางอย่างมันยาวนานกว่านั้น ถึงลองเขียนแบบ flush stream / streaming ดู

ตัวจำลองเวลาโหลดโดยสุ่มถ่วงเวลาให้เหมือนจริง

<?php

set_time_limit(0);

header('Cache-Control: no-cache');
header('Content-Type: text/event-stream');

function task($ad, $message, $progress = '')
{
    $data = [
        'id' => $ad,
        'message' => $message,
        'progress' => $progress,
    ];

    echo json_encode($data);

    ob_flush();
    flush();
}

/* loop processing  */
for ($a = 1; $a <= 10; $a++) {
    task($a, 'on iteration ' . $a . ' of 10', $a * 10);

    sleep(rand(1, 10));
}

task('CLOSE', 'Process complete');

ตัวอย่างการใช้ jQuery.ajax()

<!DOCTYPE>
<html>

<head>
    <title>Flushed ajax test</title>
    <meta charset="UTF-8" />
    <style>
        #results {
            background: #eee;
            border: 1px solid #c00000;
            height: 250px;
            overflow: auto;
            padding: 10px;
            width: 98%;
        }
    </style>
</head>

<body>
    <div id="results" style=""></div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script>
        var last_response_len = false;
        $.ajax('stream.php', {
                xhrFields: {
                    onprogress: function(e) {
                        var this_response, response = e.currentTarget.response;
                        if (last_response_len === false) {
                            this_response = response;
                            last_response_len = response.length;
                        } else {
                            this_response = response.substring(last_response_len);
                            last_response_len = response.length;
                        }
                        console.log(this_response);
                        data = $.parseJSON(this_response);
                        console.log(data);
                        $('#results').append('<br>' + data.message);
                    }
                }
            })
            .done(function(data) {
                console.log('Complete response = ' + data);
                $('#results').append('<br><br>Complete response = ' + data);
            })
            .fail(function(data) {
                console.log('Error: ', data);
            });
        console.log('Request Sent');
    </script>
</body>

</html>

ถ้าดูใน console.log จะเห็นว่าตัวแปร data มันจะโดนเพิ่มขึ้นมาเรื่องๆ ดังนั้นถ้ามี response มาจาก server เยอะๆ ก็ต้องแก้ไข code ด้วย

update วิธีเขียนให้ง่ายขึ้นและทำงานบน nginx ได้ ตามที่เขียนใน NGINX: แสดงผลลัพธ์ทันที

<?php

set_time_limit(0);

header('Cache-Control: no-cache');
header('Content-Type: text/event-stream');
header('X-Accel-Buffering: no');

set_time_limit(0);

ob_implicit_flush(true);
ob_end_flush();

function task($ad, $message, $progress = '')
{
    $data = [
        'id' => $ad,
        'message' => $message,
        'progress' => $progress,
    ];

    echo json_encode($data);
}

/* loop processing  */
for ($a = 1; $a <= 10; $a++) {
    task($a, 'on iteration ' . $a . ' of 10', $a * 10);

    sleep(rand(1, 10));
}

task('CLOSE', 'Process complete');

Byphunsanit

jQuery Ajax แบบอนุกรมตามลำดับ

งานที่ทำอยู่ต้องใช้เจคิวรี่เอแจ็คไปเรียกใช้สร้างตารางในฐานข้อมูลใหม่ แต่ถ้าใช้ ajax หลายๆ ชุดต่อๆ กันแทนที่มันจะทำงานตามลำดับแบบอนุกรม มันดันไปทำงานแบบขนานแทน บางตารางที่ต้องสร้างหลังเพราะกำหนดความสัมพันธ์ไว้กับตารางหลัก แต่ตารางหลักยังสร้างไม่เสร็จ ผลคือ การสร้างตารางทำไม่สำเร็จ

แก้ได้โดยบังคับให้ รอฟังก์ชั่นเดิมเสร็จก่อนแล้วจึงทำงานอื่นๆ ต่อไป

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery Ajax Synchronous By Pitt Phunsanit</title>
</head>
<body>
<div id="logs"></div>
<script src="../jQuery/jquery-2.1.3.min.js"></script>
<script>
$(function(){

	logs = $('#logs');

	/* task order */
	var tasks = new Array();
	tasks.push('one');
	tasks.push('two');
	tasks.push('three');



	/* process each step */
	function step(tasks, a)
	{
		$.ajax({
			"cache" : false,
			"data" : 'task='+tasks[a],
			"dataTyp" : "html",
			"method" : "post",
			"success" : function(datas)
			{

				logs.append(datas);

				/* call next step */
				a++;
				if(typeof tasks[a] != 'undefined')
				{
					step(tasks, a);
				}

			},
			"url" : 'task.php'
		});
	}

	/* call first time */
	step(tasks, 0);
});
</script>
</body>
</html>
<?php
switch($_POST['task'])
{
	case 'one' :
	{
		echo '<h1>One</h1>';
	}break;
	case 'two' :
	{
		echo '<h1>Two</h1>';
	}break;
	case 'three' :
	{
		echo '<h1>three</h1>';
	}break;
}

ทีนี้มันจะทำงานตามลำดับ 1,2,3… อย่างถูกต้อง

ถ้าต้องการหยุดการทำงาน เช่น มี error ให้เปลี่ยนค่า a เป็นค่าที่ไม่มีอยู่จริง เช่น 9999 (คงไม่มี process กลุ่มไหนถึง) คำสั่ง typeof tasks[a] จะ return ‘undefined’ code ก็จะหยุดการทำงาน

อ่านเพิ่มเติม jQuery: Ajax รับข้อมูลแบบ stream