Tạo các ứng dụng Web di động với HTML 5, Phần 2: Mở khóa bộ nhớ cục bộ cho các ứng dụng Web di động với HTML 5

Cải thiện tốc độ của các ứng dụng di động của bạn với bộ nhớ cục bộ được chuẩn hóa

Một trong những tính năng mới có ích nhất trong HTML 5 là chuẩn hóa bộ nhớ cục bộ. Cuối cùng, các nhà phát triển Web có thể chặn đứng những phiền phức để làm cho tất cả các dữ liệu phía máy khách ăn khớp với các Cookie 4KB. Bây giờ bạn có thể lưu trữ một lượng lớn dữ liệu trên máy khách bằng một API đơn giản. Đây là một cơ chế hoàn hảo để lưu trữ dữ liệu trong bộ nhớ truy cập nhanh (cache), vì vậy bạn có thể cải thiện đáng kể tốc độ ứng dụng của bạn—một nhân tố quan trọng đối với các ứng dụng Web di động, thường dựa trên các kết nối chậm hơn nhiều so với các kết nối trên máy tính để bàn của chúng. Trong bài viết thứ hai trong loạt bài này về HTML 5, bạn sẽ thấy cách sử dụng bộ nhớ cục bộ, cách gỡ lỗi nó, và bạn sẽ thấy một loạt các cách sử dụng nó để cải thiện các ứng dụng Web di động.

Michael Galpin, Kiến trúc sư phần mềm, Ludi Labs

Michael Galpin đã phát triển phần mềm Java một cách chuyên nghiệp từ năm 1998. Ông hiện đang làm việc cho eBay. Ông đã có bằng về toán học của Viện Công nghệ California.



29 06 2010 (Xuất bản lần đầu tiên vào ngày 18 11 2011)

02.06.2010: Thêm các liên kết cho Phần 3 của loạt bài này trong các phần Giới thiệu về loạt bài này, Tóm tắt, và Tài nguyên.

08.06.2010: Thêm các liên kết cho Phần 4 của loạt bài này trong các phần Giới thiệu về loạt bài này, Tóm tắt, và Tài nguyên.

29.06.2010: Thêm các liên kết cho Phần 5 của loạt bài này trong các phần Giới thiệu về loạt bài này, Tóm tắt, và Tài nguyên.

Giới thiệu về loạt bài này

HTML 5 là một công nghệ được quảng cáo thổi phồng rất nhiều, nhưng có lý do chính đáng. Nó hứa hẹn sẽ là một điểm bùng phát công nghệ để mang các khả năng ứng dụng của máy tính để bàn đến cho trình duyệt. Do có triển vọng đối với các trình duyệt truyền thống, nên nó thậm chí còn có nhiều tiềm năng hơn cho các trình duyệt di động. Hơn nữa, các trình duyệt di động phổ biến nhất đã chấp nhận và triển khai thực hiện nhiều phần quan trọng của đặc tả HTML 5.

Trong loạt bài năm phần này, bạn sẽ xem xét kỹ hơn về một số những công nghệ mới, là một phần của HTML 5, có thể có tác động rất lớn trong việc phát triển ứng dụng Web di động. Trong mỗi phần, bạn sẽ phát triển một ứng dụng Web di động đang làm việc để giới thiệu một tính năng của HTML 5, có thể được sử dụng trên các trình duyệt Web di động hiện đại giống như các trình duyệt đã thấy trên các thiết bị iPhone và các thiết bị dựa vào-Android.


Các điều kiện cần trước

Các từ viết tắt thông dụng

  • API: Giao diện lập trình ứng dụng
  • CSS: Bảng định kiểu xếp chồng
  • DOM: Mô hình đối tượng tài liệu
  • HTML: Ngôn ngữ đánh dấu siêu văn bản
  • HTTP: Giao thức truyền siêu văn bản
  • JSON: Ký hiệu đối tượng JavaScript
  • JSONP: JSON có lớp đệm
  • SDK: Bộ công cụ cho nhà phát triển phần mềm
  • UI: Giao diện người dùng
  • URL: Trình định vị tài nguyên thống nhất
  • W3C: Hiệp hội mạng toàn cầu

Trong bài viết này, bạn sẽ phát triển các ứng dụng Web bằng các công nghệ Web mới nhất. Hầu hết các mã có ở đây chỉ là HTML, JavaScript và CSS — các công nghệ lõi của nhà phát triển Web bất kỳ. Điều quan trọng nhất mà bạn sẽ cần là các trình duyệt để thử nghiệm các ứng dụng. Hầu hết mã trong bài viết này sẽ chạy trên các trình duyệt mới nhất, có một số trường hợp ngoại lệ cần lưu ý. Tất nhiên bạn cũng phải thử nghiệm trên các trình duyệt di động, và bạn sẽ cần có các bản iPhone SDK và Android SKD mới nhất cho các trình duyệt đó. Trong bài viết này có sử dụng iPhone SDK 3.1.3 và Android SDK 2.1. Xem phần Tài nguyên để biết các liên kết.


101 bộ nhớ cục bộ

Các nhà phát triển Web đã phải vật lộn với việc lưu trữ dữ liệu trên máy khách suốt nhiều năm qua. Người ta cho rằng các Cookie HTTP đã bị lạm dụng cho mục đích này. Các nhà phát triển đã nén khối lượng dữ liệu đáng kinh ngạc này vào trong một vùng nhớ 4KB do đặc tả HTTP phân bổ. Lý do rất đơn giản. Các ứng dụng Web tương tác cần lưu trữ dữ liệu với nhiều lý do khác nhau, và để lưu trữ dữ liệu đó trên một máy chủ thì thường không hiệu quả, không an toàn, hoặc không thích hợp. Đã có một số cách tiếp cận thay thế khác cho vấn đề này trong nhiều năm qua. Các trình duyệt khác nhau đã giới thiệu các API bộ nhớ độc quyền. Các nhà phát triển cũng đã sử dụng các khả năng bộ nhớ mở rộng trong Flash Player bằng cách trưng ra điều này thông qua JavaScript. Tương tự như vậy, Google đã tạo ra trình cắm thêm Gears cho các trình duyệt khác nhau, và nó cũng bao gồm các API bộ nhớ. Không có gì đáng ngạc nhiên, một số các thư viện JavaScript đã cố gắng giải quyết ổn thỏa những khác biệt này. Nói cách khác, các thư viện này cung cấp một API đơn giản, và sau đó kiểm tra xem các khả năng bộ nhớ nào đã có (có thể là một API trình duyệt độc quyền hoặc có thể là một trình cắm thêm như Flash).

Thật may mắn cho các nhà phát triển Web, cuối cùng đặc tả HTML 5 cũng có một chuẩn cho bộ nhớ cục bộ, được một loạt các trình duyệt khác nhau triển khai thực hiện. Trên thực tế, chuẩn này đã là một trong các chuẩn được thông qua nhanh nhất và được hỗ trợ trong các phiên bản mới nhất của tất cả các trình duyệt lớn: Microsoft®, Internet Explorer®, Mozilla Firefox, Opera, Apple Safari, và Google Chrome. Thậm chí quan trọng hơn nữa đối với các nhà phát triển di động là, chuẩn này được hỗ trợ trong các trình duyệt dựa trên WebKit như đã thấy trong các máy iPhone và các máy điện thoại sử dụng Android (phiên bản 2.0 hoặc mới hơn) cũng như các trình duyệt di động khác như Fennec của Mozilla. Với suy nghĩ ấy, chúng ta hãy xem xét API này.

Các Storage API

localStorage API (API bộ nhớ cục bộ) khá đơn giản. Trên thực tế, với mỗi đặc tả HTML 5, API này triển khai thực hiện giao diện DOM Storage (Bộ nhớ DOM). Lý do của sự khác biệt này là HTML 5 chỉ rõ hai đối tượng riêng biệt thực hiện giao diện này, localStoragesessionStorage. Đối tượng sessionStorage là triển khai thực hiện Storage (Bộ nhớ) chỉ để lưu trữ dữ liệu trong một phiên làm việc. Chính xác hơn, ngay khi không có kịch bản lệnh nào đang chạy để có thể truy cập sessionStorage, trình duyệt này có thể xóa dữ liệu sessionStorage trong thời gian rỗi của nó. Điều này là trái ngược với localStorage, thường kéo dài qua các phiên làm việc của nhiều người dùng. Hai đối tượng này chia sẻ cùng một API, vì vậy tôi sẽ chỉ tập trung vào localStorage.

Storage API (API bộ nhớ) là một cấu trúc dữ liệu của cặp tên/giá trị kinh điển. Các phương thức phổ biến nhất mà bạn sẽ sử dụng là getItem(name)setItem(name, value). Chúng làm việc chính xác như bạn có thể mong đợi: getItem trả về giá trị liên quan đến tên hoặc null (không) nếu tên đó không tồn tại, trong khi setItem hoặc thêm các cặp tên/giá trị vào localStorage hoặc thay thế một giá trị hiện có. Ngoài ra còn có một removeItem(name), như tên gọi này cho thấy, loại bỏ một cặp tên/giá trị khỏi localStorage nếu có một cặp tên/giá trị hoặc không làm gì khác cả. Cuối cùng, để lặp lại qua tất cả các cặp tên/giá trị này, có hai API. Một API là đặc tính chiều dài, cung cấp cho bạn tổng số các cặp tên/các giá trị đang được lưu. Đi cùng với API này là, một phương thức key(index) trả về một tên từ một mảng có tất cả các tên được dùng trong bộ nhớ.

Với các API đơn giản này, bạn có thể làm được nhiều thứ. Một vài ví dụ có thể là việc cá nhân hóa hoặc theo vết hành vi người dùng. Các ví dụ này có thể là các trường hợp sử dụng quan trọng cho các nhà phát triển Web di động, nhưng có một điều quan trọng hơn cả là: lưu trữ trong bộ nhớ truy cập nhanh (cache). Với localStorage, bạn có thể dễ dàng lưu trữ dữ liệu từ các máy chủ của bạn, trên máy tính cục bộ của khách. Điều này cho phép bạn tránh phải chờ đợi các cuộc gọi lại chậm tiềm năng đến các máy chủ của bạn và giảm thiểu lượng dữ liệu cần thiết từ các máy chủ của bạn. Bây giờ hãy xem xét một ví dụ giải thích cách sử dụng localStorage để đạt được kiểu lưu trữ trong bộ nhớ truy cập nhanh này.


Ví dụ: Lưu trữ bằng bộ nhớ cục bộ

Ví dụ này dựa vào một ví dụ mà bạn đã bắt đầu phát triển lần đầu trong Phần 1 của loạt bài này. Ví dụ đó đã cho thấy cách thực hiện tìm kiếm cục bộ của Twitter nhờ nhận được vị trí của một người dùng bằng các geolocation API (API định vị địa lý). Bắt đầu với ví dụ đó, hãy làm đơn giản nó, và sau đó làm tăng hiệu năng cho nó. Để bắt đầu, hãy mở ví dụ này ra để chỉ tìm kiếm Twitter không có định vị địa lý. Liệt kê 1 cho thấy ứng dụng tìm kiếm Twitter được đơn giản hóa.

Liệt kê 1. Tìm kiếm Twitter cơ bản nhất
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name = "viewport" content = "width = device-width"/>
<title>Basic Twitter Search</title>
<script type="text/javascript">
    function searchTwitter(){
        var query = "http://search.twitter.com/search.json?callback
=showResults&q=";
        query += $("kwBox").value;
        var script = document.createElement("script");
        script.src = query;
        document.getElementsByTagName("head")[0].appendChild(script);
    }
    // ui code deleted for brevity
    function showResults(response){
        var tweets = response.results;
        tweets.forEach(function(tweet){
            tweet.linkUrl = "http://twitter.com/" + tweet.from_user 
+ "/status/" + tweet.id;
        });
        makeResultsTable(tweets);
    }
</script>
<!--  CSS deleted for brevity -->
</head>
<body>
    <div id="main">
        <label for="kwBox">Search Twitter:</label>
        <input type="text" id="kwBox"/>
        <input type="button" value="Go!" onclick="searchTwitter()"/>
    </div>
    <div id="results">
    </div>
</body>
</html>

Trong ứng dụng này, bạn sử dụng sự hỗ trợ của các API tìm kiếm Twitter cho JSONP. Khi người dùng gửi đi một tìm kiếm, một cuộc gọi API được thực hiện bằng cách thêm động một thẻ kịch bản lệnh vào trang đó và chỉ rõ tên của một hàm callback. Điều này cho phép bạn thực hiện cuộc gọi giữa các miền (cross-domain) từ một trang Web. Ngay khi cuộc gọi này trả về, hàm callback (showResults) được gọi ra. Bạn có thêm một địa chỉ URL liên kết đến mỗi mẩu tin (tweet) được Twitter trả về và sau đó tạo ra một bảng đơn giản hiển thị các mẩu tin này. Để tăng tốc độ cho việc này, bạn có thể lưu trữ các kết quả của một truy vấn tìm kiếm trong bộ nhớ truy cập nhanh và sử dụng các kết quả đã lưu này bất cứ khi nào người sử dụng gửi đi một truy vấn. Để bắt đầu, hãy xem xét cách sử dụng localStorage để lưu trữ các mẩu tin cục bộ.

Lưu trữ cục bộ

Tìm kiếm Twitter cơ bản sẽ cung cấp một loạt các mẩu tin từ API tìm kiếm Twitter. Nếu bạn có thể lưu các mẩu tin này cục bộ và kết hợp chúng với việc tìm kiếm từ khóa để tạo ra chúng, thì bạn có một bộ nhớ truy cập nhanh có thể sử dụng được. Để lưu các mẩu tin này, bạn chỉ cần thay đổi hàm callback, sẽ được gọi ra khi cuộc gọi đến API tìm kiếm Twitter trả về. Liệt kê 2 cho thấy các hàm đã thay đổi.

Liệt kê 2. Tìm kiếm và lưu trữ
function searchTwitter(){
    var keyword = $("kwBox").value;
    var query = "http://search.twitter.com/search.json?callback
=processResults&q=";
    query += keyword;
    var script = document.createElement("script");
    script.src = query;
    document.getElementsByTagName("head")[0].appendChild(script);
}
function processResults(response){
    var keyword = $("kwBox").value;
    var tweets = response.results;
    tweets.forEach(function(tweet){
        saveTweet(keyword, tweet);
        tweet.linkUrl = "http://twitter.com/" + tweet.from_user + "/status/" + tweet.id;
    });
    makeResultsTable();
    addTweetsToResultsTable(tweets);
}
function saveTweet(keyword, tweet){
    // check if the browser supports localStorage
    if (!window.localStorage){
        return;
    }
    if (!localStorage.getItem("tweet" + tweet.id)){
        localStorage.setItem("tweet" + tweet.id, JSON.stringify(tweet));
    }
    var index = localStorage.getItem("index::" + keyword);
    if (index){
        index = JSON.parse(index);
    } else {
        index = [];
    }
    if (!index.contains(tweet.id)){
        index.push(tweet.id);
        localStorage.setItem("index::"+keyword, JSON.stringify(index));
    } 
}

Hãy bắt đầu với hàm đầu tiên, searchTwitter. Hàm này được gọi khi một tìm kiếm được người dùng gửi đi. Điều duy nhất đã thay đổi so với Liệt kê 1 là hàm callback. Thay vì chỉ hiển thị các mẩu tin khi chúng quay lại, bạn cần xử lý chúng (lưu chúng cũng như hiển thị chúng). Vì vậy, bạn chỉ rõ một hàm callback mới, processResults. Bạn lấy ra từng mẩu tin và gọi saveTweet. Bạn cũng chuyển qua từ khóa đã được dùng để tạo ra các kết quả tìm kiếm. Đó là do bạn muốn kết hợp các mẩu tin này với từ khoá đó.

Trong hàm saveTweet, hãy bắt đầu bằng cách kiểm tra để chắc chắn rằng localStorage thực sự được trình duyệt hỗ trợ. Như đã đề cập ở trên, localStorage được hỗ trợ rộng rãi trong cả hai trình duyệt máy tính để bàn và trình duyệt di động, nhưng luôn cần kiểm tra là một ý tưởng tốt khi sử dụng một tính năng mới như thế này. Nếu nó chưa được hỗ trợ, thì bạn chỉ đơn giản trả về từ hàm này. Không có gì sẽ được lưu trữ, cũng nhưng không có lỗi nào được đưa ra cả — đơn giản là ứng dụng sẽ không có bộ nhớ truy cập nhanh trong trường hợp này. Nếu localStorage được hỗ trợ, thì trước tiên kiểm tra xem mẩu tin đó đã được lưu trữ chưa. Nếu nó chưa được lưu trữ, thì hãy lưu nó cục bộ bằng cách sử dụng setItem. Tiếp theo, lấy ra một đối tượng index (chỉ mục) tương ứng với từ khóa. Đối tượng này chỉ đơn giản là một mảng các ID của các mẩu tin có liên quan đến từ khóa đó. Nếu ID của mẩu tin đó không phải là một phần của chỉ mục, thì hãy thêm nó vào và cập nhật chỉ mục đó.

Lưu ý rằng khi bạn lưu và tải Liệt kê 3, bạn đã sử dụng JSON.stringifyJSON.parse. Đối tượng JSON (hay chính xác hơn, window.JSON) là một phần của đặc tả HTML 5 như là một đối tượng native (nguyên gốc) luôn có mặt. Phương thức stringify của nó sẽ biến đối tượng JavaScript bất kỳ thành một chuỗi tuần tự, trong khi phương thức parse của nó lại làm ngược lại. Đối tượng JSON khôi phục một đối tượng JavaScript từ biểu diễn chuỗi tuần tự của nó. Điều này là cần thiết do localStorage chỉ lưu các chuỗi. Tuy nhiên, đối tượng JSON nguyên gốc không được triển khai thực hiện rộng rãi như localStorage. Ví dụ, nó không có mặt trong trình duyệt Mobile Safari mới nhất trên iPhone (phiên bản 3.1.3 vào lúc viết bài này). Nhưng nó được hỗ trợ trên các trình duyệt Android mới nhất. Bạn có thể dễ dàng kiểm tra xem đối tượng JSON nguyên gốc có ở đó không, và, nếu không có, hãy nạp một tệp JavaScript bổ sung. Bạn có thể thu được đối tượng JSON tương tự được sử dụng nguyên gốc bằng cách truy cập vào trang Web json.org (xem Tài nguyên). Để xem các chuỗi tuần tự này trông giống như thế nào theo cục bộ, bạn có thể sử dụng các công cụ trình duyệt khác nhau để kiểm tra những gì được lưu trữ trong localStorage với một trang Web cụ thể. Hình 1 cho thấy một số mẩu tin đã lưu trong bộ nhớ truy cập nhanh được lưu trữ cục bộ và có thể xem chúng bằng Các công cụ của nhà phát triển của Chrome.

Hình 1. Các mẩu tin đã lưu trong bộ nhớ truy cập nhanh
Ảnh chụp màn hình về một danh sách các mẩu tin đã lưu trong bộ nhớ truy cập nhanh (có các trường Khóa và giá trị)

Cả Chrome lẫn Safari đều có các công cụ phát triển dựng sẵn cho phép bạn xem bất kỳ dữ liệu nào đang được lưu trong localStorage. Điều này có thể rất có ích cho việc gỡ lỗi các ứng dụng sử dụng localStorage. Nó cho bạn thấy các cặp khóa/giá trị được lưu trữ cục bộ bằng văn bản thuần. Bây giờ bạn đã bắt đầu lưu các mẩu tin đến từ các API tìm kiếm của Twitter sao cho có thể sử dụng chúng như một bộ nhớ truy cập nhanh, bạn chỉ cần bắt đầu đọc chúng từ localStorage. Hãy xem xét cách làm điều này tiếp theo.

Tải dữ liệu cục bộ nhanh chóng

Trong Liệt kê 2, bạn đã thấy một số ví dụ đọc từ localStorage bằng cách sử dụng phương thức getItem của nó. Bây giờ khi người dùng gửi đi một tìm kiếm, bạn có thể kiểm tra với một truy cập vào bộ nhớ truy cập nhanh và ngay lập tức tải các kết quả đã lưu trữ. Tất nhiên, bạn vẫn sẽ truy vấn dựa vào API tìm kiếm của Twitter, do mọi người nhắn và cập nhật các mẩu tin mọi lúc và thêm vào các kết quả tìm kiếm. Tuy nhiên, bây giờ bạn cũng được trang bị theo cách để làm cho việc truy vấn thậm chí trở nên hiệu quả hơn bằng cách chỉ yêu cầu các kết quả mà bạn vẫn chưa có trong bộ nhớ truy cập nhanh. Liệt kê 3 cho thấy mã tìm kiếm được cập nhật.

Liệt kê 3. Tìm kiếm cục bộ trước tiên
function searchTwitter(){
    if ($("resultsTable")){
        $("resultsTable").innerHTML = ""; // clear results
    }
    makeResultsTable();
    var keyword = $("kwBox").value;
    var maxId = loadLocal(keyword);
    var query = "http://search.twitter.com/search.json?callback=processResults&q=";
    query += keyword;
    if (maxId){
        query += "&since_id=" + maxId;
    }
    var script = document.createElement("script");
    script.src = query;
    document.getElementsByTagName("head")[0].appendChild(script);
}
function loadLocal(keyword){
    if (!window.localStorage){
        return;
    }
    var index = localStorage.getItem("index::" + keyword);
    var tweets = [];
    var i = 0;
    var tweet = {};
    if (index){
        index = JSON.parse(index);
        for (i=0;i<index.length;i++){
            tweet = localStorage.getItem("tweet"+index[i]);
            if (tweet){
                tweet = JSON.parse(tweet);
                tweets.push(tweet);
            }
        }
    }
    if (tweets.length < 1){
        return 0;
    }
    tweets.sort(function(a,b){
        return a.id > b.id;
    });
    addTweetsToResultsTable(tweets);
    return tweets[0].id;
}

Điều đầu tiên mà bạn cần lưu ý là khi gửi đi một tìm kiếm, trước tiên bạn gọi hàm loadLocal mới. Hàm này trả về một số nguyên là ID của mẩu tin mới nhất được tìm thấy trong bộ nhớ truy cập nhanh. Hàm loadLocal lấy một keyword (từ khóa), do từ khóa này được dùng để tìm các mẩu tin liên quan trong bộ nhớ truy cập nhanh localStorage. Nếu bạn có một maxId, thì hãy sử dụng nó để thay đổi truy vấn đến Twitter, thêm vào tham số since_id. Bạn đang ra lệnh cho Twitter API chỉ trả về các mẩu tin mới hơn so với ID đã cho trong tham số này. Về tiềm năng, điều này có thể làm giảm số lượng các kết quả quay lại từ Twitter. Bất cứ lúc nào bạn có thể tối ưu hóa các cuộc gọi của máy chủ với một ứng dụng Web di động, điều đó thực sự có thể cải thiện trải nghiệm người dùng trên các mạng di động chậm. Bây giờ xem kỹ hơn về loadLocal.

Trong hàm loadLocal, bạn sử dụng các cấu trúc dữ liệu được lưu trữ trước trong Liệt kê 2. Trước tiên bạn nạp chỉ mục liên quan đến từ khóa bằng cách sử dụng phương thức getItem. Nếu không thấy có chỉ mục nào, thì cũng không có các mẩu tin nào được lưu trữ trong bộ nhớ cache, vì vậy không có gì để hiển thị và không thể thực hiện tối ưu hóa trên truy vấn này (và bạn trả về một giá trị 0 để chỉ thị điều này). Nếu tìm thấy một chỉ mục, thì bạn sẽ nhận được danh sách về các ID từ nó. Từng mẩu tin trong các mẩu tin này được lưu trữ trong bộ nhớ truy cập nhanh cục bộ, vì vậy bạn chỉ phải sử dụng phương thức getItem một lần nữa để tải từng mẩu tin trong số chúng khỏi bộ nhớ truy cập nhanh. Các mẩu tin được tải rồi được sắp xếp. Sử dụng hàm addTweetsToResultsTable để hiển thị các mẩu tin, và sau đó trả về ID của mẩu tin mới nhất. Trong ví dụ này, mã để nhận được các mẩu tin mới, trực tiếp gọi hàm để cập nhật giao diện người dùng. Bạn có thể gặp khó khăn với mã này vì nó tạo ra ghép tương tác giữa mã để lưu trữ và lấy ra các mẩu tin và mã để hiển thị chúng, tất cả đều thông qua hàm processResults. Việc sử dụng các sự kiện lưu trữ cung cấp một cách tiếp cận được ghép tương tác ít hơn, thay thế.

Các sự kiện bộ nhớ

Bây giờ mở rộng ứng dụng ví dụ để cho thấy 10 thuật ngữ tìm kiếm hàng đầu (Top 10) có các kết quả được lưu trữ trong bộ nhớ truy cập nhanh nhiều nhất. Điều này có thể mô tả các tìm kiếm mà người dùng gửi đi nhiều nhất. Liệt kê 4 cho thấy một hàm để tính toán Top 10 này và hiển thị nó.

Liệt kê 4. Tính toán 10 tìm kiếm hàng đầu
function displayStats(){
    if (!window.localStorage){ return; }
    var i = 0;
    var key = "";
    var index = [];
    var cachedSearches = [];
    for (i=0;i<localStorage.length;i++){
        key = localStorage.key(i);
        if (key.indexOf("index::") == 0){
            index = JSON.parse(localStorage.getItem(key));
            cachedSearches.push ({keyword: key.slice(7), numResults: index.length});
        }
    }
    cachedSearches.sort(function(a,b){
        if (a.numResults == b.numResults){
            if (a.keyword.toLowerCase() < b.keyword.toLowerCase()){
                return -1;
            } else if (a.keyword.toLowerCase() > b.keyword.toLowerCase()){
                return 1;
            }
            return 0;
        }
        return b.numResults - a.numResults;
    }).slice(0,10).forEach(function(search){
        var li = document.createElement("li");
        var txt = document.createTextNode(search.keyword + " : " + search.numResults);
        li.appendChild(txt);
        $("stats").appendChild(li);
    });
}

Hàm này gây ấn tượng nhiều hơn về localStorage API. Bạn bắt đầu bằng cách nhận được tổng số các mục được lưu trữ trong localStorage và sau đó lặp lại qua chúng. Nếu mục này có một chỉ mục, thì bạn phân tích cú pháp đối tượng và tạo ra một đối tượng đại diện cho dữ liệu mà bạn liên quan đến: từ khóa liên quan đến chỉ mục và số lượng của các mẩu tin trong chỉ mục. Dữ liệu này được lưu trữ trong một mảng gọi là cachedSearches. Tiếp theo, phân loại cachedSearches, đặt các tìm kiếm có các kết quả nhiều nhất đầu tiên, rồi sử dụng sắp xếp theo thứ tự chữ cái có phân biệt chữ hoa, chữ thường nếu hai tìm kiếm có cùng một số kết quả được lưu trữ trong bộ nhớ cache. Sau đó lấy ra 10 tìm kiếm hàng đầu, tạo HTML cho mỗi tìm kiếm, và viết thêm chúng vào một danh sách theo thứ tự. Hãy gọi hàm này khi tải trang đầu tiên, như trong Liệt kê 5.

Liệt kê 5. Khởi tạo trang
window.onload = function() {
    displayStats();
    document.body.setAttribute("onstorage", "handleOnStorage();");
}

Trong Liệt kê 4 dòng đầu tiên gọi hàm này khi tải trang. Việc tải thứ hai ở nơi mà mọi thứ thú vị hơn. Ở đây bạn thiết lập một trình xử lý sự kiện cho sự kiện onstorage. Sự kiện này khởi động bất cứ khi nào hàm localStorage.setItem kết thúc thực hiện. Điều này cho phép bạn tính lại 10 tìm kiếm hàng đầu. Liệt kê 6 cho thấy trình xử lý sự kiện này.

Liệt kê 6. Trình xử lý sự kiện bộ nhớ
function handleOnStorage() {
    if (window.event && window.event.key.indexOf("index::") == 0){
        $("stats").innerHTML = "";
        displayStats();
    }
}

Sự kiện onstorage sẽ được liên kết với cửa sổ. Nó có một số đặc tính có ích: key (khóa), oldValue (giá trị cũ), và newValue (giá trị mới). Ngoài các đặc tính tự giải thích này, nó cũng có một địa chỉ url (URL của trang đã thay đổi giá trị) và source (cửa sổ có chứa kịch bản lệnh đã thay đổi giá trị). Hai đặc tính cuối cùng này có ích hơn khi một người dùng có thể có nhiều cửa sổ hoặc thẻ (tab) hoặc thậm chí cả iFrames cho ứng dụng của bạn, không có đặc tính nào trong số đó là đặc biệt phổ biến trong các ứng dụng di động. Quay lại Liệt kê 6, đặc tính duy nhất mà bạn thực sự cần là key. Bạn sử dụng key để xem đã có một chỉ mục đã bị thay đổi không. Nếu đúng, thì bạn thiết lập lại danh sách top 10 và lấy nó ra bằng cách gọi lại hàm displayStats. Ưu điểm của kỹ thuật này là không có hàm khác nào cần biết về danh sách top 10 vì nó là khép kín.

Tôi đã đề cập ở trên rằng DOM Storage nói chung, trong đó bao gồm cả hai localStoragesessionStorage, là một tính năng HTML 5 đã được chấp nhận rộng rãi. Tuy nhiên, các sự kiện bộ nhớ là một ngoại lệ cho điều này — ít nhất là trên các trình duyệt máy tính để bàn. Tại thời điểm viết bài này, các trình duyệt máy tính để bàn duy nhất hỗ trợ các sự kiện bộ nhớ là Safari 4+ và Internet Explorer 8+. Firefox, Chrome hay Opera không hỗ trợ nó. Tuy nhiên, trong thế giới di động mọi đều thứ tốt hơn một chút. Cả hai phiên bản mới nhất của các trình duyệt iPhone và Android đều hỗ trợ hoàn toàn các sự kiện bộ nhớ, và tất cả các mã được trình bày ở đây đều chạy tốt với chúng.


Tóm tắt

Là một nhà phát triển, bạn có thể cảm thấy được giải phóng rất nhiều khi bạn đột nhiên có một số lượng lớn không gian lưu trữ trên máy khách. Đối với các nhà phát triển Web dài hạn, nó mở ra những điều mà họ có thể đã muốn làm suốt nhiều năm qua, nhưng vẫn chưa có một cách tốt để tạo ra chúng mà không dựa vào các thủ thuật có nhiều lỗi. Đối với các nhà phát triển di động, nó thậm chí còn thú vị hơn vì nó thực sự mở ra việc lưu trữ dữ liệu trong bộ nhớ truy cập nhanh cục bộ. Ngoài cải thiện đáng kể hiệu năng của ứng dụng của bạn, việc lưu trữ dữ liệu trong bộ nhớ truy cập nhanh cục bộ là chìa khóa để cho phép khả năng thú vị mới khác của các ứng dụng Web di động: hoạt động không nối mạng. Đó sẽ là chủ đề cho bài viết tiếp theo trong loạt bài này.


Tải về

Mô tảTênKích thước
Article source codelocal.zip8KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=775362
ArticleTitle=Tạo các ứng dụng Web di động với HTML 5, Phần 2: Mở khóa bộ nhớ cục bộ cho các ứng dụng Web di động với HTML 5
publish-date=06292010