(Post 15/11/2005)
Trong khoảng thời gian gần đây, các nhà cung cấp dịch
vụ Web trên thế giới đang chạy đua nâng cấp dung lượng hộp mail nhằm chiếm
lấy một số lượng thị phần đáng kể, người sử dụng không còn quan tâm nhiều
đền dung lượng hộp mail như trước đây, thay vào đó họ bắt đầu quan tâm
nhiều đến tốc độ duyệt mail.
Tôi là một trong số những người luôn ngạc nhiên trước
tốc độ xử lý của Gmail (http://gmail.google.com).
Cảm giác của tôi khi dùng Gmail rất giống như một ứng dụng desktop: khi
nhấp vào một liên kết, thay vì phải đợi cả trang Web tải lại, mọi thứ
hiện ra gần như tức thì. Với sự ra đời của Gmail và những trang Web khác
như Google Maps (http://map.google.com),
Google Suggest (http://www.google.com/webhp?complete=1&hl=en)
của Google, tất cả cộng đồng sử dụng Internet trên thế giới đều nhận ra
rằng một ứng dụng trên Web cũng có thể tốt như một ứng dụng cài đặt trên
máy của họ.
Gần đây tôi có nghe giải thích trên một tờ báo tin học
rằng sở dĩ Gmail có thể nhanh như vậy là dùng ActiveX. Nhưng nếu bạn thử
Gmail trên Firefox hay Opera, tốc độ của ứng dụng cũng không hề thay đổi
mà hai trình duyệt này không hề có khái niệm về ActiveX - một công nghệ
độc quyền của Microsoft.
Vậy bí quyết nào đứng đằng sau các trang web này của
Google? Đó là một “công nghệ” có cái tên gợi tới một CLB bóng đá của Hà
Lan: AJAX.
1. Vậy AJAX là gì?
Nó mới chỉ xuất hiên lần đầu vào tháng 2 năm nay (2005),
khi Jesse James Garrett của
công ty AdapativePath định nghĩa và tóm gọn lại từ cụm từ “Asynchronous
JavaScript+CSS+DOM+XMLHttpRequest”. Ngay sau đó cụm
từ AJAX được phổ biến cực kỳ nhanh chóng trong cộng đồng phát triển Web
và đến giờ nó là một trong những từ khóa được tìm kiếm nhiều nhất trên
Internet. Và đây là định nghĩa của Garrett về AJAX:
AJAX không phải là một công nghệ. Nó là tập hợp của
nhiều công nghệ với thế mạnh của riêng mình để tạo thành một sức mạnh
mới. AJAX bao gồm:
- Thể hiện web theo tiêu chuẩn XHTML và CSS;
- Nâng cao tính năng động và phản hồi bằng DOM (Document Object Model
);
- Trao đổi và xử lý dữ liệu bằng XML và XSLT;
- Truy cập dữ liệu theo kiểu bất đồng bộ (asynchronous) bằng XMLHttpRequest;
- Và tất cả các kỹ thuật trên được liên kết lại với nhau bằng JavaScript.
Đến đây có lẽ bạn đang tự nhủ: có vẻ đây là một công
nghệ rất phức tạp. Không hẳn vậy! Điểm mấu chốt của Ajax nằm ở XMLHttpRequest.
Đây là một kỹ thuật do Microsoft khởi xướng và tích hợp lần đầu
tiên vào IE5 dưới dạng một ActiveX. Mozilla tích hợp công nghệ này vào
Mozilla 1.0/Netscape 6 sau đó. Và dĩ nhiên tất cả các version của Firefox
đều hỗ trợ XMLHttpRequest, hiện nay đã có trong trình duyệt Safari 1.2
(Apple) và Opera 8 trở lên. Chúng ta sẽ trở về với XMLHttpRequest và cách
sử dụng nó trên các trình duyệt khác nhau ở phần sau.
Bây giờ hãy thử một ứng dụng đơn giản sử dụng AJAX: Mobile
Phone Catalog tại liên kết này:
http://www.myjavaserver.com/~quangvhg/MobileCatalog.jsp
Đây là một danh sách các model điện thoại di động,
tính năng của chúng xếp theo tên hãng chế tạo.
Khi bạn đánh dấu hộp kiểm chọn các nhãn hiệu, lập tức
danh sách điện thoại của các các hãng xuất hiện ngay ở bảng phía dưới
mà không cần tải lại cả trang Web.
So với cách thông thường, khi người dùng có một cần thay
đổi dữ liệu trên trang Web, yêu cầu thay đổi được gửi về server dưới dạng
HTTP request (hay còn gọi postback), server sẽ xử lý yêu cầu này và gửi
trả lại trang HTML khác thay thế trang cũ. Qui trình này được mô tả là
nhấp-chờ và tải lại (click-wait-and-refresh): ví dụ người dùng sau khi
nhấn một nút “Submit” trên trang web phải chờ cho đến khi server xử lý
xong mới có thể tiếp tục công việc. Ngược lại, trong ví dụ trên bạn có
thể nhấn liên tục vài hộp kiểm để chọn/bỏ chọn các nhãn hiệu mà không
cần chờ đợi.
Đây là mô hình “cổ điển” của một ứng dụng Web:
Và đây là mô hình sử dụng AJAX:
Rõ ràng điểm khác biệt là thay vì phải tải cả trang Web
thì với AJAX bạn chỉ cần tải về phần của trang Web mà bạn muốn thay đổi.
Điều này giúp cho ứng dụng Web của bạn phản hồi nhanh hơn, thông minh
hơn. Ngoài ra, điểm đặc biệt quan trọng trong công nghệ AJAX nằm ở chữ
A (Asynchronous) – bất đồng bộ – tức là bạn cứ gửi yêu cầu của mình tới
server và quay lại với công việc của mình mà không cần chờ trả lời. Khi
nào server xử lý xong yêu cầu của bạn, nó sẽ báo hiệu và bạn có thể “bắt
lấy” để thể hiện những thay đổi cần thiết. Vậy tất cả cơ chế này hoạt
động thực sự thế nào? Chúng ta sẽ xem có gì trong source code của ví dụ
Mobile Phone Catalog.
2. Digging into source code
Thông thường một ứng dụng AJAX cần có hai thành phần
(hay nhiều hơn): tạm gọi là front-end và back-end. Front-end dùng để thể
gửi các XMLHttpRequest và thể hiện các thay đổi, còn back-end để xử lý
các request và trả lại kết quả thay đổi cho front-end. Trong Mobile Phone
Catalog, trang front-end (MobileCatalog.jsp ) rất đơn giản và không có
gì thú vị ngoại trừ đoạn mã JavaScript. Mỗi khi người dùng chọn/bỏ chọn
một hộp kiểm sẽ kích hoạt hàm displayItems():
function displayItems() {
var params = "brands=";
// check to see which checkboxes are checked and append them to the string.
if (document.getElementById('checkBox1').checked ==
true) {
params += ",Nokia"
}
// more here
...
retrieveURL("MobileCatalogRender.jsp?" + params);
return true;
}
Hàm này sẽ xem có những nhãn hiệu nào được chọn và tạo
nên một chuỗi (String) request. (ví dụ nếu “Nokia” và “Samsung” được chọn
thì chuồi này sẽ có dạng “MobileCatalogRender.jsp?brands=,Nokia,Samsung”)
và gửi chuỗi này tới hàm retrieveURL(). Đây là hàm quan trọng nhất nên
ta sẽ xem xét kỹ từng dòng và ý nghĩa của các dòng lệnh này:
1. function retrieveURL(url) {
2. if (window.XMLHttpRequest) { // Non-IE browsers
3. req = new XMLHttpRequest();
4. req.onreadystatechange = processStateChange;
5. try {
6. req.open("GET", url, true);
7. } catch (e) {
8. alert(e);
9. }
10. req.send(null);
11. } else if (window.ActiveXObject) { // IE
12. req = new ActiveXObject("Microsoft.XMLHTTP");
13. if (req) {
14. req.onreadystatechange = processStateChange;
15. req.open("GET", url, true);
16. req.send();
17. }
18. }
19. }
- Dòng 2/dòng 11: Kiểm tra xem trình duyệt có hỗ trợ
XMLHttpRequest hay không. Trong đó dòng 11 dùng cho trình duyệt của Microsoft
- Internet Explorer (như các bạn thấy chúng ta phải tạo một ActiveX) còn
dòng 2 dùng cho các trình duyệt khác (Mozilla, Safari, Opera).
- Dòng 3/dòng 12: khời tạo đối tượng XMLHttpRequest.
- Dòng 4/dòng 14: Gán event handler khi có phản hồi. Đây là dòng lệnh
có ý nghĩa đặc biệt, nó cho phép chúng ta nhận phản hồi của back-end và
cập nhật các thay đổi trên front-end.
- Dòng 6/dòng 15+16: Gửi request từ front-end tới back-end dưới dạng một
HTTP request. Ở đây chuỗi request là “MobileCatalogRender.jsp?brands=,Nokia,Samsung”.
Sau khi gửi request đi, nếu có bất kỳ phản hồi gì từ
back-end hàm processStateChange() sẽ được kích hoạt. Trong trường hợp
lý tưởng back-end sẽ trả về một bảng danh sách các model điện thoại di
động của hai hãng Nokia và Samsung. Hàm processStateChange() sẽ gán đoạn
HTML trả về này vào div “theTable”, ngược lại sẽ hiện lên một thông báo
lỗi:
function processStateChange() {
if (req.readyState == 4) { // Complete
if (req.status == 200) { // OK response
document.getElementById("theTable").innerHTML = req.responseText;
} else {
alert("Problem: " + req.statusText);
}
}
}
Cuối cùng là mã của back-end (MobileCatalogRender.jsp).
Đây là một trang Java Server Page có nhiệm vụ xử lý request và trả lại
một bảng dữ liệu tương ứng (bạn có hoàn toàn có thể dùng một servlet thay
cho trang này). Đây là trích mã nguồn, chắc các bạn có thể dễ dàng hiểu
được.
String param1 = (String)request.getParameter("brands");
String displayPicture = (String)request.getParameter("picture");
if (param1 == null) {
param1 = "";
}
if (displayPicture == null) {
displayPicture = "no";
}
String[] brands = param1.split(",");
ArrayList mobiles = new ArrayList();
for(int j=0; j<brands.length; j++){
if(brands[j].equalsIgnoreCase("nokia")){
mobiles.add(nokia1());
mobiles.add(nokia2());
mobiles.add(nokia3());
}
if(brands[j].equalsIgnoreCase("samsung")){
mobiles.add(samsung1());
mobiles.add(samsung2());
mobiles.add(samsung3());
}
if(brands[j].equalsIgnoreCase("motorola")){
mobiles.add(moto1());
mobiles.add(moto2());
mobiles.add(moto3());
}
}
// And yes, I know creating HTML in an Action
is generally very bad form,
// but I wanted to keep this exampel simple.
String html = "<table border=\"0\" align=\"center\"
cellpadding=\"1\" cellspacing=\"0\" width=\"100%\"
class=DataGrid1>";
html += "<tr class=DataGrid2Header>";
html += "<th>Model</th>";
html += "<th>Trọng Lượng</th>";
html += "<th>Kích Thước</th>";
html += "<th>Bộ Nhớ</th>";
html += "<th>Màn Hình</th>";
html += "<th>Giá (triệu đ)</th>";
if(displayPicture.equalsIgnoreCase("yes"))
html += "<th>Hình</th>";
html += "</tr>";
int row =0;
for (Iterator it = mobiles.iterator(); it.hasNext();) {
HashMap hm = (HashMap)it.next();
if(row%2 == 0)
html += "<tr class=DataGrid1Style align=center>";
else
html += "<tr class=DataGrid1StyleAlternate align=center>";
html += "<td valign=middle>" + (String)hm.get("model")
+ "</td>";
html += "<td valign=middle>" + (String)hm.get("weight")
+ "</td>";
html += "<td valign=middle>" + (String)hm.get("size")
+ "</td>";
html += "<td valign=middle>" + (String)hm.get("RAM")
+ "</td>";
html += "<td valign=middle>" + (String)hm.get("graphic")+
"</td>";
html += "<td valign=middle>" + (String)hm.get("price")+
"</td>";
if(displayPicture.equalsIgnoreCase("yes"))
html += "<td valign=middle><img src=\""
+ myWebPath + "images/mobile/" + (String)hm.get("picture")+
"\"></td>";
html += "</tr>";
row++;
}
html += "</table>";
// Write the HTML to response
out.write(html);
3. Một vài ví dụ khác:
Tuy các ví dụ ở đây viết bằng Java, AJAX không bó hẹp
ở J2EE mà có thể thực hiện ở các nền tảng khác như .Net hay PHP.
Hy vọng bài viết này sẽ có ích phần nào với các bạn.
(theo JavaVietNam Organization) |