Trong khi làm việc với một ứng dụng, đặc biệt là một ứng dụng của n−ớc ngoài, ng−ời dùng sẽ phải t−ơng tác liên tục với ứng dụng. Việc duy trì t−ơng tác một cách liên tục ở đây rất quan trọng. Trong khi thực hiện hoạt động dài, nếu mọi đối t−ợng bị khóa, hoạt động của ng−ời dùng sẽ bị gián đoạn. –Ph−ơng thức gọi dị bộ đ−ợc đ−a ra nh− là cách để cải thiện hoạt động giao diện ng−ời dùng khi thực hiện những phiên giao dịch hoặc các hoạt động dài. Do tác dụng của trễ mạng nên ta coi tất cả các cuộc gọi tới server đều là các cuộc gọi dài.
Một thực tế ta phải chấp nhận đó là tài liệu sẽ bị khoá cho tới khi server trả lời. Để có thể làm việc liên tục với tài liệu ta có một số cách thức thực hiện một yêu cầu dị bộ tới ng−ời dùng. Hai kỹ thuật đ−ợc sử dụng đó là IFrames, và trong thời gian gần đây là kỹ thuật XMLHttpRequest.
5.1 IFrames
Iframe là cụm từ viết tắt của: inline, có nghĩa là nó là một phần của một lớp tài liệu khác có trong một tập Frame. Một IFrame đ−ợc thể hiện bằng một thành phần trong cây DOM, do vậy ta có thể di chuyển, định lại kích cỡ, ẩn…trong khi vẫn nhìn thấy trang. B−ớc ngoặt đến khi ng−ời ta bắt đầu nhận ra rằng một IFrame có thể đ−ợc định dạng sao cho nó hoàn toàn ẩn đi. Điều này cho phép nó cập nhật dữ liệu trong trang gốc, trong khi ng−ời dùng vẫn đang hoạt động. Cơ chế để tiếp xúc với server là dị bộ.
Cũng giống nh− các thành phần DOM khác, ta có thể khai báo một IFrame trong HTML cho một trang hoặc nó có thể tự động tạo ra khi sử dụng hàm document.creatElement(). Trong tr−ờng hợp đơn giản, ta chỉ muốn một IFrame để tải dữ liệu, ta khai báo nó nh− là một phần của tài liệu, tạo một điều khiển bằng cách sử dụng document.getElementById(): <html> <head> <script type=’text/javascript’> window.onload=function(){ var iframe=document.getElementById(‘dataFeed’); var src=’datafeeds/mydata.xml’; loadDataAsynchronously(iframe,src); } function loadDataAsynchronously(iframe,src){ ……….. } </script> </head> <body>
ở đây IFrame đ−ợc ẩn đi. Ta định dạng ẩn bằng việc thiết lập độ rộng và chiều cao của nó bằng 0. Ta cũng có thể sử dụng kiểu display : none. Tuy nhiên. Ta cần đợi tài liệu đ−ợc load hết tr−ớc khi tìm kiếm IFrame qua hàm gọi getElementById() trong hàm điều khiển window.onload. Ta cũng có thể tạo các IFrame theo yêu cầu theo cách sau:
function fetchData(){
var iframe=document.creatElement(‘iframe’); iframe.className=’hiddentDataFeed’;
document.body.appendChild(iframe); var src=’datafeeds/mydata.xml’; loadDataAsynchronously(iframe,src); }
Điểm thuận lợi ở đây là ta có thể l−u tất cả các mã có liên quan tới việc yêu cầu dữ liệu tại một địa điểm, tốt hơn là phải duy trì tính đồng bộ ID của node DOM giữa giữa kịch bản và HTML.
Hình 2.3: Chuỗi các sự kiện xử lý dị bộ trong trang web.
Hoạt động ng−ời dùng liên quan tới một yêu cầu từ một đối t−ợng yêu cầu ẩn (một Iframe hoặc một đối t−ợng XMLHttpRequest ), đây là một lệnh gọi tới server dị bộ. Ph−ơng thức trả về rất nhanh, giao diện ng−ời sử dụng bị khoá trong một thời gian rất ngắn.
5.2 Các đối t−ợng XmlDocument và XMLHttpRequest
Các IFrame có thể đ−ợc sử dụng để yêu cầu dữ liệu.Tuy vậy những phiên bản trình duyệt web sau này đã đ−a vào các đối t−ợng cho mục đích truyền dữ liệu dị bộ và chúng thuận tiện hơn so với các IFrame.
Các đối t−ợng XmlDocument và XMLHttpRequest là những đối t−ợng mở rộng không chuẩn tắc của DOM đ−ợc phần lớn các nhà trình duyệt web hỗ trợ. Chúng đ−a ra lộ trình thực hiện các cuộc gọi dị bộ, do chúng đ−ợc thiết kế để đ−a dữ liệu vào trong môi truờng gốc. Cả hai đối t−ợng trên đều do Microsoft tạo ra, có trong các đối t−ợng JavaScript trong trình duyệt IE. Các trình duyệt khác sử dụng các đối t−ợng t−ơng tự, và các lệnh gọi API. Trong hai loại trên, XMLHttpRequest đ−ợc sử dụng nhiều hơn, cung cấp nhiều điều khiển hơn. Do đó ta chỉ sử dụng XMLHttpRequest.
Hàm sau đây tạo ra một đối t−ợng XMLHttpRequest
Function getXMLDocument(){ Var xDoc=null;
If (document.implement
&& document.implementation.createDocumnet){
xDoc=document.implementation.createDocumnet(“”,””,null);} else if (typeof ActiveXObject !=”undefined”){
var msXmlAx==null; try{ msXmlAx=new ActiveXObject(“Msxml12.DomDocument”);} catch (e){ msXmlAx=new ActiveXObject(“Msxml.DomDocument”); } xDoc=msXmlAx; }
if (xDoc==null || typeof xDoc.load==”undefined”){ xDoc=null;}
return xDoc; }
Hàm trên tạo ra một đối t−ợng XmlDocument với một API mà hầu hết các trình duyệt ngày nay có thể nhận biết đ−ợc.
Ch−ơng trình kiểm tra xem đối t−ợng có hỗ trợ đặc tính cần thiết để tạo ra một đối t−ợng XmlDocument. Nếu ch−ơng trình không tìm đ−ợc các hỗ trợ, ch−ơng trình sẽ trả về đối t−ợng ActiveXlDocument().
Cần chú ý rằng ta có thể kiểm tra các phiên bản cũng nh− thông tin của các trình duyệt. Nhờ đó giúp cho việc thực hiện kịch bản đ−ợc dễ dàng hơn.
Function getXMLHTTPRequest() { Var xRequest=null;
If (window.XMLHttpRequest){ xRequest=new XMLHttpRequest();
}else if (typeof ActiveXObject !=”ubdefined”){
xRequest=new ActiveXObject(“Microsoft.XMLHTTP”); }
return xRequest; }
Đây là cách thức thực hiện hàm XMLHttpRequest đơn giản hơn. Trong hàm này ta có sử dụng lệnh phát hiện đối t−ợng để kiểm tra các hỗ trợ đối t−ợng HttpRequest, nếu không có các hỗ trợ ch−ơng trình sẽ tự động trả về một ActiveX. Nếu nh− trình duyệt không hỗ trợ cả hai, khi đó ch−ơng trình sẽ trả về giá trị null.
Nh− vậy, ta có thể tạo ra một đối t−ợng để gửi yêu cầu tới server giúp chúng ta.
5.3 Gửi yêu cầu tới server
Việc gửi yêu cầu tới server thông qua đối t−ợng XMLHttpRequest khá đơn giản. Ta chỉ cần chuyển URL tới trang server mà tạo ra dữ liệu cho chúng ta. Ví dụ: Function sendRequest(url,params,HttpMethod){ If (!HttpMethod){ HttpMethod=”POST”; } var req=getXMLHTTPRequest(); if (req){ req.open(HttpMethod,url,true); req.setRequetHeader (“content-Type”, “application/x-www-form-urlenclosed”); req.send(params); } }
XMLHttpRequest hỗ trợ một số l−ợng lớn các cú pháp gọi HTTP, bao gồm các tham số hàng đợi cho các trang đ−ợc tạo tự động (Ví dụ nh− là các tham số CGI, các tham số ServeletRequest hoặc các argument Forms phụ thuộc vào sự phat triển của server.)
5.4 Sử dụng các hàm gọi ng−ợc để giám sát các yêu cầu.
B−ớc thứ 2 của quá trình điều khiển truyền thông dị bộ là thiết lập một điểm gần nhất trong đoạn mã để nhận kết quả của một lệnh gọi khi nó kết thúc. ở đây ta sẽ đăng ký một hàm gọi ng−ợc, thực chất là một đoạn mã có liên quan khi có các kết quả, tại một số điểm ch−a chỉ định tr−ớc trong t−ơng lai. Hàm
window.onload mà chúng ta đề cập ở trên trong đoạn 2.9 là một hàm gọi ng−ợc.
Các hàm gọi ng−ợc phù hợp với ch−ơng trình đ−ợc điều khiển qua sự kiện, đ−ợc sử dụng trong hầu hết các công cụ trong giao diện ng−ời dùng – ấn bàn phím, click chuột… sẽ xảy ra tại những điểm không chính xác trong t−ơng lai, và các nhà lập trình kiểm soát nó bằng việc viết một hàm để quản lý các sự kiện đó khi chúng xảy ra. Khi viết các sự kiện giao diện ng−ời dùng bằng JavaScript, ta đăng ký các hàm onkeypress, onmouseover, cũng nh− các đặc tính theo tên của đối t−ợng. Khi viết các hàm gọi ng−ợc yêu cầu server, chúng ta đ−a thêm các đặc tính nh− onload và onreadystatechange.
Một điều khiển hàm gọi ng−ợc (callback fuction ) đơn giản nh− sau:
Var READY_STATE_UNINITIALIZED=0; Var READY_STATE_LOADING=1; Var READY_STATE_LOADED=2; Var READY_STATE_INTERACTIVE=3; Var READY_STATE_COMPLETE=4; Var req; Function sendRequest(url,params,HttpMethod){ If (!HttpMethod){ HttpMethod=”GET”; } req=getXMLHTTPRequest(); if (req){ req.onreadystatechange=onreadyStateChange; req.open(HttpMethod,url,true); req.setRequestHeader (“Content-Type”,”application/x-www-form-urlenclose”); } }
function onreadyStateChange(){ var ready=req.readyState; var data=null if (ready=READY_STATE_COMPLETE){ data=req.responseText; }else{ data=”loading…[“+ready+”]”; }
//…do something with the data… }
Ta định nghĩa một hàm điều khiển gọi ng−ợc onReadystateChange(). Có một số giá trị cho trạng thái sẵn sàng. Ta đăng ký các biến cho từng giá trị đó. Trong phần này, ch−ơng trình chỉ kiểm tra giá trị 4, t−ơng ứng với trạng thái yêu cầu đã hoàn thành.
ở đây, ta khai báo đối t−ợng yêu cầu là biến toàn cục. Nhờ đó giúp ta duy trì mọi thứ một cách đơn giản trong khi chúng ta đánh địa chỉ cơ chế của đối t−ợng XMLHttpRequest, tuy nhiên chính điều này sẽ dẫn đến một số vấn đề cho ta nếu ta cố gằng duy trì một số yêu cầu cùng một lúc. Ta sẽ xử lý vấn đề này trong phần sau.
Ch−ơng II: Cách Sử dụng Ajax trong ứng dụng I. Phát triển và duy trì cơ sở dữ liệu
1.1. Giới thiệu:
Để xây dựng một ứng dụng Ajax hoàn chỉnh, ta cần phải có những công cụ để thực hiện công việc. Một trong những đối t−ợng cần quan tâm đầu tiên đó là những cách thức quản lý cơ sở dữ liệu lớn và phức tạp. Do Ajax là một công cụ đột phá trong lĩnh vực xây dựng web cho nên cần phải quản lý Ajax theo một cách thức riêng. Cách thức tốt nhất để thực hiện các công việc đó chính là xây dựng hệ thống dựa trên những mô hình thiết kế.
Công cụ chính mà ta sử dụng là refractoring. Refactoring giúp duy trì mã ch−ơng trình đ−ợc trong sáng, bảo vệ và cho phép ta đối mặt với những thay đổi theo yêu cầu mà không sợ bất cứ điều gì. Ta cần nhận thức một điều rằng refactoring cũng nh− các mô hình thiết kế th−ờng đ−ợc sử dụng tại những vị trí mà chúng có thể phát huy đ−ợc hiệu quả của mình. Để công việc đ−ợc thực hiện đạt kết quả mong muốn, yêu cầu quyết yếu là tìm ra đ−ợc những mô hình thiết kế ứng dụng hiệu quả, dùng đúng lúc, đúng chỗ.
1.2 Refactoring
Trong các đoạn ch−ơng trình, việc thực hiện yêu cầu từ client đến server thông qua XMLHttpRequest là quan trong nhất. Yêu cầu đó đ−ợc thể hiện qua hàm senRequest(). SendRequest() kích hoạt hàm initHttpRequest() để tìm đối t−ợng XMLHttpRequest. Hàm trả về là onReadyState(). Đối t−ợng XMLHttpRequest đ−ợc định nghĩa là một biến toàn cục, do đó hàm trả về có thể sử dụng nó. Quá trình điều khiển sau đó bao gồm việc điều khiển các thông tin trạng thái đối t−ợng yêu cầu và các thông tin gỡ rối.
Về nguyên tắc, khi thực hiện một yêu cầu tới server, điều ta quan tâm chính là những kết quả trả về ứng với những hoạt động của ng−ời dùng. Để đ−a hoạt động của ng−ời dùng vào đoạn ch−ơng trình hiện tại, ta cần phải thay
đổi các xử lý của hàm onReadyState().
Việc sử dụng các biến toàn cục cũng là một vấn đề quan trọng. Nếu nh− ta thực hiện một vài yêu cầu tới server cùng một lúc, khi đó ta cần phải tạo ra khả năng đăng ký các điều khiển cho các trả về của từng yêu cầu đó.
Do ta có một danh sách các tài nguyên cần cập nhật, nếu ta tập trung vào một tài nguyên và bỏ qua các tài nguyên khác. Điều quan trọng ta cần biết chúng là gì và chúng hoạt động nh− thế nào?
Với lập trình h−ớng đối t−ợng, ng−ời ta xử lý các hàm yêu cầu trong một đối t−ợng. JavaScript hỗ trợ các loại mã lập trình h−ớng đối t−ợng giúp ta có thể thực hiện công việc đ−ợc dễ dàng. Gọi đối t−ợng là ContentLoader, thực hiện tải nội dung từ server. Về lý t−ởng ta có thể tạo ra một đối t−ợng, chuyển nó vào trong URL, khi đó yêu cầu sẽ đ−ợc gửi đi. Ta có thể chuyển giá trị mẫu tới phần điều khiển gọi ng−ợc của ng−ời dùng để thực hiện, nếu nh− tài liệu đ−ợc tải thành công. Trong tr−ờng hợp không thành công, sẽ có hoạt động khác đ−ợc thực hiện. Lệnh gọi đối t−ợng có thể có dạng nh− sau:
Var loader net.ContentLoader (‘mydata.xml’,parseMyData)
trong đó parseMyData là một hàm gọi ng−ợc đ−ợc sử dụng khi tải dữ liệu thành công.
1.3. Các mô hình sử dụng refactoring
Trong từng tr−ờng hợp khác nhau ta có những cách thức sắp xếp lại khác nhau, làm giảm những khó khăn, nhận dạng các đối t−ợng trong giải pháp mà có thể đ−ợc sử dụng lại đ−ợc.
Trong một số tr−ờng hợp cụ thể, những mô hình thiết kế nhỏ tỏ ra khá hiệu quả. Đó là mô hình Cross-browser, mô hình tập lệnh, mô hình singleton. Các mô hình này còn đ−ợc gọi là các mô hình kiến trúc.
- Cross-browser: các mô hình t−ơng thích và Facade.
Hình 2.4: Chu trình thực hiện trong mô hình Facade
- Quản lý các điều khiển sự kiện: mô hình giám sát
- Sử dụng lại các điều khiển hoạt động ng−ời dùng: Mô hình tập lệnh
Hình 2.6:Mô hình tập lệnh trong ứng dụng xử lý văn bản
- Duy trì chuẩn cho tài nguyên: Mô hình singleton
II. Mô hình MVC: Model-View- Controller
2. 1 Giới thiệu
Mô hình MVC: Mô hình- Khung nhìn - Điều khiển (Model-View- Controller) là một mô hình giúp ta tổ chức dự án Ajax theo nhiều cách khác nhau, giúp dễ dàng mã hoá và quản lý các dự án này. MVC đ−ợc sử dụng để chia tách các phần ch−ơng trình t−ơng tác với ng−ời dùng với phần thực hiện các công việc khác trong ứng dụng.
Mô hình MVC có 3 vai trò quan trọng trong hệ thống. Model thể hiện các vấn đề của ứng dụng. Bộ xử lý từ sẽ là mô tả một tài liệu; một ứng dụng bản đồ sẽ mô tả các điểm trên một l−ới.
View là phần ch−ơng trình mà thể hiện những thứ với ng−ời dùng: dạng đầu vào, tranh ảnh, dạng text hoặc widgets. View không cần đồ hoạ. Trong ch−ơng trình đ−ợc cài âm, dạng âm thanh cũng là View.
Yêu cầu đầu tiên đối với MVC là View và Model không trao đổi với nhau, bởi vì đấy là nơi mà Controller hoạt động. Khi ng−ời dùng ấn một phím hoặc điền vào một mẫu nào đấy, khi đó View sẽ trao đổi thông tin với bộ điều khiển. Bộ điều khiển khi đó sẽ thông tin cho Model và mô tả thời điểm những thay đổi trong View yêu cầu Model cập nhận.
Mô hình MVC th−ờng đ−ợc áp dụng cho các ứng dụng web cơ bản theo những cách đặc biệt. Khi một ứng dụng Ajax đang đ−ợc chạy và yêu cầu dữ liệu từ server, cơ chế của việc dành dữ liệu là khá giống với cách thức của ứng dụng web truyền thống .
2. 2 Web server MVC
Nhìn chung, các ứng dụng web đã quá quen với mô hình MVC. Một ứng dụng web tạo ra một số tách biệt giữa giữa View và Model, do chúng nằm trên các máy khác nhau. Tuy nhiên ta có thể viết một ứng dụng web mà có khả năng kết hợp các mô hình này với nhau, tại một số điểm nhất định.
Hầu hết các thành phần của MVC trên Web thực hiện xử lý trang HTML, và ch−ơng trình mà tạo ra nó ( ví dụ là View ) khác xa so với những gì ng−ời dùng thực sự nhìn thấy khi trang này yêu cầu. Trong tr−ờng hợp một ứng dụng Ajax cung cấp dữ liệu cho một client JavaScript, View từ ứng dụng này chính là tài liệu XML sẽ đ−ợc trả về cho client d−ới dạng đáp ứng HTTP.
Hình 2.9:Cách thức thực hiện một yêu cầu qua mạng
2.2.1 Các vấn đề nảy sinh với khả năng sử dụng lại các đoạn kịch bản.
Trong các ứng dụng web, các thành phần của một ứng dụng th−ờng đ−ợc lặp đi lặp lại. Với Ajax, công việc của ta đơn giản chỉ là sử dụng lại các đoạn kịch bản đã có sẵn. Tuy nhiên khi áp dụng các đoạn kịch bản khác nhau
vào những vị trí khác nhau trong một ứng dụng cũng gặp một số vấn đề nảy sinh. Bao gồm:
- V−ớng mắt với hàng đợi SQL trong trang. Nếu muốn tìm kiếm theo loại hoặc từ khoá, cần phải thay đổi lại việc tạo SQL. Ta có thể phải chịu một tập trạng thái if tích luỹ qua thời gian khi chúng ta càng thêm nhiều chức năng tìm kiếm, và tất nhiên số l−ợng các tham số tìm kiếm sẽ tăng lên.
- Gặp khó khăn với dạng dữ liệu XML trong trang. Có một vài lý do tại sao ta muốn thay đổi dạng dữ liệu.
- Khó khăn với cơ sở dữ liệu đ−ợc sử dụng để tạo ra XML. Do ta duy trì một cơ sở dữ liệu kết nối mở mọi lúc khi đang tạo XML, nên sẽ không có bất cứ thao tác gì phức tạp trong vòng lặp while(), vì thế kết nối sẽ không đ−ợc lâu, thậm chí còn xuất hiện hiện t−ợng thắt cổ chai. Cũng nh− vậy, cơ sở dữ liệu để