Article:
Load-on-demand Javascript và CSS
2442
|
id.cntt.tv/cuongx Updated over 4 years ago |
Cơ sở để thực hiện Lazy load
Các thẻ trong một trang HTML thực chất là một cấu trúc cây, tạm gọi là cây DOM (bạn gọi thế nào cũng được, miễn là dễ nhớ và dễ hình dung). Để tìm thẻ nào thì duyệt cái cây DOM thông qua biến tòan cục document (đây là một đối tượng quản lý các tài nguyên và thẻ html – thẻ gốc của cây DOM).
Có thể thêm, chèn mới hay xóa 1 thẻ bất kỳ trên cây DOM này.
Cấu trúc 1 trang html giản lược như sau:
<html>
<head></head>
<body></body>
</html>
Cặp thẻ html là thẻ gốc của cây DOM (root element), các tài nguyên được đặt trong cặp thẻ head, nội dung trang html được đặt trong cặp thẻ body.
Thêm 1 thẻ mới (thêm 1 nút mới vào cây DOM) làm như sau:
node.appendChild(newNode); // node = thẻ HTML
Xóa 1 thẻ đang tồn tại (xóa 1 nút khỏi cây DOM) làm như sau:
parentNode.removeChild(node); // parent node là nút chứa node cần xóa
Chèn thêm 1 nút vào cây DOM trong bài viết này không cần đến, tìm trên Internet là có.
Trở lại với vấn đề chính: file Javascript to và nhiều quá, giải quyết thế nào?
Chủ đề Cởi trói cho Javascrip có dẫn ra vài cái link để giải quyết vấn đề:
- Sử dụng tool lằm giảm kích thước file Javascript, gọi là cruncher(xóa comment và xóa các dấu trống vô ích) và obfuscator (thay thế các tên biến/hàm dài bằng các tên viết tắt ngắn hơn, chỉ độ 2 hoặc 3 ký tự). Cách này rất hay nhưng cũng chỉ giảm đến 1 giới hạn mà thôi, ko giảm mãi được. Thêm 1 vấn đề nữa: bản quyền – Tác giải framework hay thư viện bạn dùng có cho phép bạn làm điều này hay không? Đa số là không vì bạn vi phạm nguyên tắc chia sẻ mã nguồn cho những người khác. Cách này chỉ làm đc khi bạn là tác giả của đống mã Javascript đó mà thôi.
- Các cách khác thì không hay:
- Mã hóa source của file Javascript bằng cách mã ASCII hoặc nén thành file zip đều “rất chuối”. Ko phải trình duyệt nào cũng giải nén đựoc file zip, và tốn thời gian giải nén (cả file mã hóa theo ASCII hoặc zip).
- Cache file Javascript phía server: tốn tài nguyên server mà không giải quyết được vấn đề—trình duyệt xử lý file Javascript chứ ko phải server Tạo plugin cho trình duyệt hỗ trợ cache các file Javascript: rất ít người sẽ cài plugin, nếu có thì cũng tốn tài nguyên phía người dùng.
Cách Lazy load ở đây là sự bổ sung thêm cho các tool cruncher/obfuscator nhưng có thể dùng hòan tòan độc lập mà không phải dùng đến các tool cruncher/obfuscator.
Nếu để ý kỹ sẽ thấy cặp thẻ head chứa các link đến file Javascript như sau:
<head> <script language=Javascript src=uri></script> </head>
Đây chính là một nút trong cây DOM. Tại sao không thêm 1 nút mới hoặc xóa các nút ko cần thiết nhỉ (tương đương thêm mới hay xóa đi 1 file Javascript không cần thiết)? 1 ý kiến hay! Đó chính là ý tưởng của Lazy load: chỉ tải về tài nguyên khi cần dùng đến.
Thuật tóan và cách tiến hành
Thuật tóan tiến hành như sau:- Tìm xem file 1 Javascript chứa mã cần chạy đã có chưa. Nếu có rồi thì không thêm mới làm gì, nếu chưa chuyển sang bước tiếp theo.
- Chèn thêm nút
- Xóa thẻ
- Để tìm tất cả các thẻ chứa link đến file Javascript sử dụng lệnh sau: var tags = document.getElementsByTagName(“SCRIPT”); Có thể tìm mọi thẻ có trong trang html, chỉ cần thay tên thẻ là được, nhưng lưu ý là tên phải phải viết hoa.
Bước tiếp theo là kiểm tra xem thuộc tính src của các thẻ script đã có file Javascript mới hay chưa bằng cách duyệt tòan bộ mảng các thẻ và check như sau:
if (file_js_mới == tags[i]) thoát // file javascript đã tồn tại
else thêm mới file javascript
- Để chèn thêm cặp thẻ script mới vào trang html, phải tìm thẻ cặp thẻ head (thẻ quản lý các file javascript, ko cần để ý đến các thẻ script có trong body, phần tìm các thẻ script ở trên đã tìm đầy đủ, ko sót cái nào). Để đơn giản, lấy thẻ head đầu tiên (đề phòng trường hợp có nhiều hơn 1 thẻ head trong file html):
var tags = document.getElementsByTagName("HEAD");
var headTag = tags[0];
Việc còn lại thì đơn giản rồi, sử dụng:
headTag.appendChild(newScriptNode);
là xong.
Tạo 1 nút script làm như sau:
var newScriptNode = document.createElement(“SCRIPT”); /* nhớ là phải dùng chữ hoa */
newScriptNode.src = “file_js_mới”;
- Xóa 1 file javascript khỏi trang html làm tương tự.
Kỹ thuật này áp dụng cho cả các file CSS, nhưng nhớ là link đến file CSS bằng thẻ <link href="file_css"></link>
Lớp CJsCssManager
Lớp này do tôi viết để thực hiện kỹ thuật trên. Bạn dùng nó thỏai mái: xử lý qua tool cruncher/obfuscator hoặc biến đổi nó tùy ý, bỏ hết phần tên tôi cũng ko sao.
Tạo đối tượng thực thi:
var r = new CJsCssManager();
Thêm file mới:
r.addJS("file_js_mới.js"); // thêm mới
r.addCSS("file_css_mới.css"); // thêm mới
Xóa file đang tồn tại:
r.removeJS(“file_js_đang_tồn_tại.js”); // xóa file JS
r.removeCSS(“file_css_đang_tồn_tại.css”); // xóa file CSS
Đừng quên đuôi file là .js và .css
Tuy chỉ chạy thử trên IE 6 và Firefox trên Windows, nhưng chắc là tương thích với cả với IE 5.x và Firefox trên Linux. Opera, Safari, Konqueror… thì chưa thử. Download
Tổng kết
Kỹ thuật trên giúp giảm việc tải file Javascript ngay lúc khởi đầu, rất tốn thời gian. Nó được áp dụng rất nhiều trong các ứng dụng Ajax. Tuy nhiên không nên lạm dụng kỹ thuật này, vì càng thêm nhiều file Javascript và file CSS thì càng khó kiểm sóat.
Để biết thêm về cruncher/obfuscator bạn có thể tham khảo thêm bài Che dấu và làm gọn mã nguồn.
1 2 
JavaScript
172