Giới thiệu
Việc các ứng dụng dựa trên nền tảng web có thể truy cập được khi không có mạng ngày càng trở nên quan trọng. Có, tất cả trình duyệt đều có thể lưu các trang và tài nguyên vào bộ nhớ đệm trong thời gian dài nếu được yêu cầu, nhưng trình duyệt có thể loại bỏ từng mục khỏi bộ nhớ đệm bất cứ lúc nào để tạo không gian cho các mục khác. HTML5 giải quyết một số vấn đề gây phiền toái khi ở chế độ ngoại tuyến bằng giao diện ApplicationCache. Việc sử dụng giao diện bộ nhớ đệm mang lại cho ứng dụng của bạn 3 lợi thế:
- Duyệt web khi không có mạng – người dùng có thể di chuyển trên toàn bộ trang web của bạn khi không có mạng
- Tốc độ – tài nguyên đến trực tiếp từ ổ đĩa, không cần đến mạng.
- Khả năng phục hồi – nếu trang web của bạn ngừng hoạt động để "bảo trì" (chẳng hạn như ai đó vô tình làm hỏng mọi thứ), người dùng của bạn sẽ nhận được trải nghiệm ngoại tuyến
Bộ nhớ đệm ứng dụng (hoặc AppCache) cho phép nhà phát triển chỉ định những tệp mà trình duyệt sẽ lưu vào bộ nhớ đệm và cung cấp cho người dùng khi không có mạng. Ứng dụng của bạn sẽ tải và hoạt động đúng cách, ngay cả khi người dùng nhấn vào nút làm mới khi đang ngoại tuyến.
Tệp kê khai bộ nhớ đệm
Tệp kê khai bộ nhớ đệm là một tệp văn bản đơn giản liệt kê các tài nguyên mà trình duyệt nên lưu vào bộ nhớ đệm để truy cập khi không có mạng.
Tham chiếu tệp kê khai
Để bật bộ nhớ đệm ứng dụng cho một ứng dụng, hãy thêm thuộc tính tệp kê khai vào thẻ html
của tài liệu:
<html manifest="example.appcache">
...
</html>
Bạn phải đưa thuộc tính manifest
vào mọi trang của ứng dụng web mà bạn muốn lưu vào bộ nhớ đệm. Trình duyệt không lưu trang vào bộ nhớ đệm nếu trang đó không chứa thuộc tính manifest
(trừ phi trang đó được liệt kê rõ ràng trong tệp kê khai). Điều này có nghĩa là mọi trang mà người dùng chuyển đến có chứa manifest
sẽ ngầm được thêm vào bộ nhớ đệm của ứng dụng.
Do đó, bạn không cần liệt kê mọi trang trong tệp kê khai. Nếu một trang trỏ đến tệp kê khai, thì không có cách nào để ngăn việc lưu trang này vào bộ nhớ đệm.
Bạn có thể xem các URL do bộ nhớ đệm ứng dụng kiểm soát bằng cách truy cập vào about://://appcache-internals/ trong Chrome. Tại đây, bạn có thể xoá bộ nhớ đệm và xem các mục nhập. Firefox có các công cụ tương tự dành cho nhà phát triển.
Thuộc tính manifest
có thể trỏ đến một URL tuyệt đối hoặc đường dẫn tương đối, nhưng URL tuyệt đối phải thuộc cùng một nguồn gốc với ứng dụng web.
Tệp kê khai có thể có bất kỳ đuôi tệp nào, nhưng cần được phân phát bằng loại mime chính xác (xem bên dưới).
<html manifest="http://www.example.com/example.mf">
...
</html>
Tệp kê khai phải được phân phát bằng loại mime text/cache-manifest
.
Bạn có thể cần thêm một loại tệp tuỳ chỉnh vào máy chủ web hoặc cấu hình .htaccess
.
Ví dụ: để phân phát loại mime này trong Apache, hãy thêm dòng sau vào tệp cấu hình của bạn:
AddType text/cache-manifest .appcache
Hoặc trong tệp app.yaml trong Google App Engine:
- url: /mystaticdir/(.*\.appcache)
static_files: mystaticdir/\1
mime_type: text/cache-manifest
upload: mystaticdir/(.*\.appcache)
Yêu cầu này đã bị loại bỏ khỏi thông số kỹ thuật cách đây một thời gian và không còn được yêu cầu bởi các phiên bản Chrome, Safari và Firefox mới nhất, nhưng bạn cần có loại mime để hoạt động trong các trình duyệt cũ và IE11.
Cấu trúc của tệp kê khai
Tệp kê khai là một tệp riêng biệt mà bạn liên kết thông qua thuộc tính tệp kê khai trên phần tử html. Tệp kê khai đơn giản sẽ có dạng như sau:
CACHE MANIFEST
index.html
stylesheet.css
images/logo.png
scripts/main.js
http://cdn.example.com/scripts/main.js
Ví dụ này sẽ lưu bốn tệp vào bộ nhớ đệm trên trang chỉ định tệp kê khai này.
Có một số điều cần lưu ý:
- Chuỗi
CACHE MANIFEST
là dòng đầu tiên và là dòng bắt buộc. - Tệp có thể thuộc một miền khác
- Một số trình duyệt đặt ra các quy định hạn chế về hạn mức bộ nhớ có sẵn cho ứng dụng của bạn. Ví dụ: trong Chrome, AppCache sử dụng một bể dùng chung bộ nhớ tạm thời mà các API ngoại tuyến khác có thể chia sẻ. Nếu bạn đang viết một ứng dụng cho Cửa hàng Chrome trực tuyến, thì việc sử dụng
unlimitedStorage
sẽ loại bỏ quy định hạn chế đó. - Nếu tệp kê khai trả về mã 404 hoặc 410, thì bộ nhớ đệm sẽ bị xoá.
- Nếu tệp kê khai hoặc tài nguyên được chỉ định trong tệp đó không tải xuống được, thì toàn bộ quá trình cập nhật bộ nhớ đệm sẽ không thành công. Trình duyệt sẽ tiếp tục sử dụng bộ nhớ đệm ứng dụng cũ trong trường hợp xảy ra lỗi.
Hãy xem một ví dụ phức tạp hơn:
CACHE MANIFEST
# 2010-06-18:v2
# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js
# Resources that require the user to be online.
NETWORK:
*
# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg
Các dòng bắt đầu bằng dấu "#" là dòng nhận xét, nhưng cũng có thể phục vụ một mục đích khác. Bộ nhớ đệm của ứng dụng chỉ được cập nhật khi tệp kê khai của ứng dụng thay đổi. Ví dụ: nếu bạn chỉnh sửa tài nguyên hình ảnh hoặc thay đổi một hàm JavaScript, thì những thay đổi đó sẽ không được lưu vào bộ nhớ đệm lại. Bạn phải tự sửa đổi tệp kê khai để thông báo cho trình duyệt làm mới các tệp đã lưu vào bộ nhớ đệm.
Tránh sử dụng dấu thời gian liên tục cập nhật hoặc chuỗi ngẫu nhiên để buộc cập nhật mỗi lần. Tệp kê khai được kiểm tra hai lần trong quá trình cập nhật, một lần ở đầu và một lần sau khi tất cả tệp đã lưu vào bộ nhớ đệm được cập nhật. Nếu tệp kê khai đã thay đổi trong quá trình cập nhật, thì có thể trình duyệt đã tìm nạp một số tệp từ phiên bản này và các tệp khác từ phiên bản khác, vì vậy, trình duyệt sẽ không áp dụng bộ nhớ đệm và thử lại sau.
Mặc dù bộ nhớ đệm có cập nhật, nhưng trình duyệt sẽ không sử dụng các tệp đó cho đến khi trang được làm mới, vì các quá trình cập nhật diễn ra sau khi trang được tải từ phiên bản bộ nhớ đệm hiện tại.
Tệp kê khai có thể có 3 phần riêng biệt: CACHE
, NETWORK
và FALLBACK
.
CACHE:
- Đây là phần mặc định cho các mục nhập. Các tệp được liệt kê trong tiêu đề này (hoặc ngay sau
CACHE MANIFEST
) sẽ được lưu vào bộ nhớ đệm một cách rõ ràng sau khi được tải xuống lần đầu tiên.NETWORK:
- Các tệp được liệt kê trong phần này có thể đến từ mạng nếu không có trong bộ nhớ đệm, nếu không thì mạng sẽ không được sử dụng, ngay cả khi người dùng đang trực tuyến. Bạn có thể thêm các URL cụ thể vào danh sách trắng tại đây hoặc chỉ cần nhập "" để cho phép tất cả URL. Hầu hết các trang web đều cần "".
FALLBACK:
- Một phần không bắt buộc chỉ định các trang dự phòng nếu không truy cập được tài nguyên. URI đầu tiên là tài nguyên, URI thứ hai là dự phòng được dùng nếu yêu cầu mạng không thành công hoặc gặp lỗi. Cả hai URI phải có cùng nguồn gốc với tệp kê khai. Bạn có thể chụp các URL cụ thể nhưng cũng có thể chụp các tiền tố URL. "images/large/" sẽ ghi lại lỗi từ các URL như "images/large/whatever/img.jpg".
Tệp kê khai sau đây xác định trang "catch-all" (offline.html) sẽ hiển thị khi người dùng cố gắng truy cập vào thư mục gốc của trang web khi không có kết nối mạng. Tệp này cũng khai báo rằng tất cả tài nguyên khác (ví dụ: tài nguyên trên một trang web từ xa) đều cần có kết nối Internet.
CACHE MANIFEST
# 2010-06-18:v3
# Explicitly cached entries
index.html
css/style.css
# offline.html will be displayed if the user is offline
FALLBACK:
/ /offline.html
# All other resources (e.g. sites) require the user to be online.
NETWORK:
*
# Additional resources to cache
CACHE:
images/logo1.png
images/logo2.png
images/logo3.png
Cập nhật bộ nhớ đệm
Khi một ứng dụng không có mạng, ứng dụng đó vẫn được lưu vào bộ nhớ đệm cho đến khi một trong những điều sau xảy ra:
- Người dùng xoá bộ nhớ dữ liệu của trình duyệt cho trang web của bạn.
- Tệp kê khai được sửa đổi. Lưu ý: việc cập nhật một tệp được liệt kê trong tệp kê khai không có nghĩa là trình duyệt sẽ lưu lại tài nguyên đó vào bộ nhớ đệm. Bạn phải thay đổi chính tệp kê khai.
Trạng thái bộ nhớ đệm
Đối tượng window.applicationCache
là quyền truy cập có lập trình vào bộ nhớ đệm ứng dụng của trình duyệt.
Thuộc tính status
của lớp này rất hữu ích để kiểm tra trạng thái hiện tại của bộ nhớ đệm:
var appCache = window.applicationCache;
switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY: // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};
Để kiểm tra bản cập nhật tệp kê khai theo phương thức lập trình, trước tiên, hãy gọi applicationCache.update()
.
Thao tác này sẽ tìm cách cập nhật bộ nhớ đệm của người dùng (yêu cầu tệp kê khai đã thay đổi).
Cuối cùng, khi applicationCache.status
ở trạng thái UPDATEREADY
, việc gọi applicationCache.swapCache()
sẽ hoán đổi bộ nhớ đệm cũ cho bộ nhớ đệm mới.
var appCache = window.applicationCache;
appCache.update(); // Attempt to update the user's cache.
...
if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache(); // The fetch was successful, swap in the new cache.
}
Tin vui là bạn có thể tự động hoá việc này. Để cập nhật người dùng lên phiên bản mới nhất của trang web, hãy thiết lập trình nghe để theo dõi sự kiện updateready
khi tải trang:
// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
} else {
// Manifest didn't changed. Nothing new to server.
}
}, false);
}, false);
Sự kiện AppCache
Như bạn dự kiến, các sự kiện bổ sung sẽ xuất hiện để theo dõi trạng thái của bộ nhớ đệm. Trình duyệt sẽ kích hoạt các sự kiện cho những việc như tiến trình tải xuống, cập nhật bộ nhớ đệm ứng dụng và điều kiện lỗi. Đoạn mã sau đây thiết lập trình nghe sự kiện cho từng loại sự kiện bộ nhớ đệm:
function handleCacheEvent(e) {
//...
}
function handleCacheError(e) {
alert('Error: Cache failed to update!');
};
// Fired after the first cache of the manifest.
appCache.addEventListener('cached', handleCacheEvent, false);
// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);
// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', handleCacheEvent, false);
// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);
// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', handleCacheEvent, false);
// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);
// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', handleCacheEvent, false);
// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', handleCacheEvent, false);
Nếu tệp kê khai hoặc tài nguyên được chỉ định trong tệp đó không tải được, thì toàn bộ quá trình cập nhật sẽ không thành công. Trình duyệt sẽ tiếp tục sử dụng bộ nhớ đệm ứng dụng cũ trong trường hợp xảy ra lỗi như vậy.
Tài liệu tham khảo
- Quy cách API ApplicationCache
- Application Cache is a douchebag (Bộ nhớ đệm của ứng dụng là một thằng khốn) – trình bày các vấn đề và điểm cần lưu ý về AppCache.