27/4/16

Bài 16: Kỹ thuật xử lý hàng đợi khi gửi ajax

Nếu bạn cần xử lý ajax nhiều lần và thứ tự thực hiện giữa các lần gửi ajax thì bạn sẽ áp dụng kỹ thuật đệ quy ajax, hay còn gọi là thiết lập hàng đợi trong ajax. Đây là một kỹ thuật cũng nâng cao và nó chủ yếu là do kinh nghiệm của mỗi người nên trong bài này mình chỉ chia sẻ kinh nghiệm của mình, nếu có gì sai mong bạn bỏ qua.
Hàng đợi là gi? hàng đợi là một khái niệm mà bạn đã học rồi nên mình không nói nhiều về. Nó có nhiều loại nhưng mình đề cập đến một loại hàng đợi giống như khi bạn xếp hàng thanh toán tiền trong siêu thị vậy, nghĩa là bạn sẽ phải xếp hàng và đi theo thứ tự ai đến trước thì được thanh toán trước, khi nào người đó thanh toán xong thì người tiếp theo mới được thanh toán. Và kỹ thuật này áp dụng vào lập trình hoàn toàn được.

1. Tình huống bài toán hàng đợi

Để các bạn dễ hiểu hơn thì mình đưa ra một ví dụ thế này.
Mình sẽ xây dựng một ứng dụng gồm một ô textbox và một button như hình sau:

Khi người dùng click vào nút Send thì chương trình sẽ tạo ra một bảng gồm 10 phần tử (10 tasks) và trạng thái của các phần tử (Waitting, Sendding, Finished). Lúc này hệ thống bắt đầu xử lý từng task bằng ajax.

Nhìn thoáng qua thì nó không ứng dụng gì nhưng nếu bạn biết cách áp dụng vào bài toán của bạn thì nó sẽ có tác dụng ngay. Ví dụ bạn viết chương trình gửi email với số lượng lớn thì bạn sẽ phải gửi từng email, lúc này danh sách hàng đợi sẽ là tổng số email. Email nào chưa gửi thì ở trạng thái Waitting, email nào đang gửi thì ở trạng thái Sendding và email nào gửi rồi thì ở trạng thái Finished.

2. Xử lý ajax theo hàng đợi

Trước tiên bạn cần tạo hai file:
  • sleep.php là file nhận request từ ajax
  • index.html là file chính
Cả hai file này cùng nằm trong một thư mục www hoặc htdocs của Webserver ảo nhé các bạn.
File sleep.php:
Vì mình demo không có sử dụng database hay gửi email nên mình sẽ dùng hàm sleep ngủ 2 giây để các bạn thấy trạng thái rõ ràng hơn. Lúc này nội dung của file như sau:
1
2
3
<?php
sleep(2);
?>
File index.html:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
        <style>
            .red{
                color: red;
            }
            .blue{
                color:blue;
            }
            .pink{
                color:pink;
            }
        </style>
        <script language="javascript">
            $(document).ready(function()
            {
                // Code
            });
        </script>
    </head>
    <body>
        <input type="text" id="num-thread" value="10"/>
        <input type="button" id="send-request" value="Send"/>
        <div id="results"></div>
    </body>
</html>
Trong file này bạn cần chú ý các điểm sau:
  • Mình khai báo 3 class CSS để hiển thị màu sắc cho các trạng thái
  • Mình có khai báo một thẻ script dùng để code JS, nên sau này những đoạn code JS sẽ được đặt vào vị trí này
  • Có một thẻ div#results dùng để hiển thị bảng task
Bây giờ chạy file lên bạn sẽ có giao diện gồm một ô input và một button như hình trên. Bây giờ ta bắt đầu code Ajax cho nó nhé.
Mình sẽ tạo hai hàm như sau:
  • Hàm display_html(num) dùng để hiển thị bảng danh sách các task như trên và tham số truyền vào là số lượng task (num)
  • Hàm send_ajax(num, index) dùng để gửi ajax và tham số truyền vào gồm số lượng task (num) và task cần gửi (index)
Hàm display_html().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function display_html(num)
{
    var html = '';
    html += '<table border="1" cellpadding="5">';
        html += '<tr>';
            html += '<td>Num</td>';
            html += '<td>Status</td>';
        html += '</tr>';
    for (var i = 0; i < num; i++){
        html += '<tr>';
            html += '<td>'+(i+1)+'</td>';
            html += '<td id="waitting'+i+'" class="pink">Waitting...</td>';
        html += '</tr>';
    }
    html += '</table>'
    $('#results').html(html);
}
Các bạn để ý mình có gán ID cho cột trạng thái với quy luật '<td id="waitting'+i+'" class="pink">Waitting...</td>'. trong đó i là số thứ tự của tas, điều này quan trọng vì hàm send_ajax() sẽ dựa vào id này để bik cần thay đổi trang thái cho task nào.
Hàm send_ajax().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function send_ajax(num, index)
{
    // Kiểm tra xem task đã hết chưa, nếu hết thì dừng
    if (index > (num - 1)){
        return false;
    }
    // Chuyển trang thái từ waitting san sendding
    $('#waitting'+index).removeClass('pink').addClass('red').html('Sending...');
    // Gửi ajax
    $.ajax({
        url : 'sleep.php',
        type : 'post',
        dataType : 'text',
        success : function()
        {
            // Sau khi thành công thì chuyển trạng thái sang finished
            $('#waitting'+index).removeClass('red').addClass('blue');
            $('#waitting'+index).html('Finished');
        }
    })
    .always(function(){
        // Xử lý task tiếp theo
        send_ajax(num, ++index);
    });
}
Ok vậy là ta đã có hai hàm, bây giờ ta sẽ viết javascript xử lý sự kiện click vào button như sau:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$('#send-request').click(function()
{  
    // Lấy số lượng task từ user nhập vào
    var num = parseInt($('#num-thread').val());
    // Ẩn textbox và button
    $(this).remove();
    $('#num-thread').remove();
    // Hiển thị table danh sách task
    display_html(num);
    // gửi ajax cho lần đầu tiên (task = 1)
    send_ajax(num, 0);
});
Ok và đây là toàn bộ file index.html.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
        <style>
            .red{
                color: red;
            }
            .blue{
                color:blue;
            }
            .pink{
                color:pink;
            }
        </style>
        <script language="javascript">
            $(document).ready(function()
            {
                // Hàm hiển thị danh sách hàng task
                function display_html(num)
                {
                    var html = '';
  
                    html += '<table border="1" cellpadding="5">';
                        html += '<tr>';
                            html += '<td>Num</td>';
                            html += '<td>Status</td>';
                        html += '</tr>';
  
                    for (var i = 0; i < num; i++){
                        html += '<tr>';
                            html += '<td>'+(i+1)+'</td>';
                            html += '<td id="waitting'+i+'" class="pink">Waitting...</td>';
                        html += '</tr>';
                    }
                    html += '</table>'
  
                    $('#results').html(html);
                }
                 
                // Hàm gửi ajax
                function send_ajax(num, index)
                {
                    // Kiểm tra xem task đã hết chưa, nếu hết thì dừng
                    if (index > (num - 1)){
                        return false;
                    }
                    // Chuyển trang thái từ waitting san sendding
                    $('#waitting'+index).removeClass('pink').addClass('red').html('Sending...');
                    // Gửi ajax
                    $.ajax({
                        url : 'sleep.php',
                        type : 'post',
                        dataType : 'text',
                        success : function()
                        {
                            // Sau khi thành công thì chuyển trạng thái sang finished
                            $('#waitting'+index).removeClass('red').addClass('blue');
                            $('#waitting'+index).html('Finished');
                        }
                    })
                    .always(function(){
                        // Xử lý task tiếp theo
                        send_ajax(num, ++index);
                    });
                }
                  
                // Khi click gửi request
                $('#send-request').click(function()
                {  
                    // Lấy số lượng task từ user nhập vào
                    var num = parseInt($('#num-thread').val());
                    // Ẩn textbox và button
                    $(this).remove();
                    $('#num-thread').remove();
                    // Hiển thị table danh sách task
                    display_html(num);
                    // gửi ajax cho lần đầu tiên (task = 1)
                    send_ajax(num, 0);
                });
            });
        </script>
    </head>
    <body>
        <input type="text" id="num-thread" value="10"/>
        <input type="button" id="send-request" value="Send"/>
        <div id="results"></div>
    </body>
</html>

3. Lời kết

Bạn hoàn toàn có thể cải tiến chương trình này bằng cách viết chương trình gửi email hàng loạt, trong đó:
  • số lượng task ở ô input bạn sẽ cho người dùng nhập danh sách email và cách nhau bởi dấu phẩy
  • file sleep.php có nhiệm vụ nhận email và gửi
  • đoạn javascript có nhiệm vụ chuyển danh sách email và đưa vào hàng đợi, sau đó gửi từng email.
Vì mình cũng hơi bận nên chỉ đưa ra ý tưởng vậy thôi, chúc các bạn thành công!
Theo code.freetuts.net

0 nhận xét: