Bộ nhớ dành cho web

Có nhiều tuỳ chọn khác nhau để lưu trữ dữ liệu trong trình duyệt. Giải pháp nào phù hợp nhất với nhu cầu của bạn?

Kết nối Internet có thể không ổn định hoặc không tồn tại khi di chuyển, đây là lý do tại sao hỗ trợ ngoại tuyến và hiệu suất đáng tin cậy là những tính năng phổ biến ở ứng dụng web tiến bộ. Ngay cả trong mạng không dây hoàn hảo môi trường, sử dụng hợp lý phương pháp lưu vào bộ nhớ đệm và các kỹ thuật lưu trữ khác cải thiện đáng kể trải nghiệm người dùng. Có một vài cách để lưu vào bộ nhớ đệm tài nguyên ứng dụng tĩnh của bạn (HTML, JavaScript, CSS, hình ảnh, v.v.) và (dữ liệu người dùng, tin bài, v.v.). Nhưng giải pháp nào là tốt nhất? Cách thức bạn có thể lưu trữ bao nhiêu? Làm cách nào để tài khoản này không bị loại trừ?

Tôi nên sử dụng công cụ gì?

Dưới đây là đề xuất chung để lưu trữ tài nguyên:

IndexedDB và API Lưu trữ bộ nhớ đệm đều được hỗ trợ trong mọi trình duyệt hiện đại. Cả hai đều không đồng bộ và sẽ không chặn luồng chính. Đó là có thể truy cập từ đối tượng window, nhân viên web và trình chạy dịch vụ, giúp dễ dàng sử dụng chúng ở bất cứ đâu trong mã.

Còn các cơ chế lưu trữ khác thì sao?

Có nhiều cơ chế lưu trữ khác trong trình duyệt, nhưng chúng có mức sử dụng hạn chế và có thể gây ra các vấn đề đáng kể về hiệu suất.

SessionStorage là một tab cụ thể và nằm trong phạm vi của thời gian tồn tại của thẻ. Điều này có thể hữu ích khi lưu trữ một lượng nhỏ các phiên hoạt động thông tin cụ thể, ví dụ: khoá IndexedDB. Nên dùng với thận trọng vì nó đồng bộ và sẽ chặn luồng chính. Đó là có kích thước giới hạn khoảng 5MB và chỉ có thể chứa các chuỗi. Do được thiết kế riêng cho từng thẻ, trình thực thi web hoặc trình chạy dịch vụ không thể truy cập tệp đó.

Bạn nên tránh sử dụng LocalStorage vì đây là dịch vụ đồng bộ và sẽ chặn luồng chính. Tệp này được giới hạn khoảng 5MB và có thể chứa chỉ chuỗi. Nhân viên web hoặc dịch vụ không thể truy cập vào LocalStorage nhân viên.

Cookie có mục đích sử dụng của chúng nhưng không nên được sử dụng để lưu trữ. Cookie được gửi cùng với mọi yêu cầu HTTP, do đó, việc lưu trữ nhiều hơn một một lượng nhỏ dữ liệu sẽ làm tăng đáng kể kích thước của mọi yêu cầu web. Các thư viện này đồng bộ và không thể truy cập được từ trình thực thi web. Thích LocalStorage và SessionStorage, cookie chỉ được giới hạn ở các chuỗi.

File System API và FileWriter API cung cấp các phương thức cho đọc và ghi tệp vào hệ thống tệp hộp cát. Mặc dù không đồng bộ, nhưng không nên dùng vì chỉ hoạt động trên các trình duyệt dựa trên Chromium.

API Truy cập hệ thống tệp được thiết kế nhằm giúp người dùng có thể dễ dàng đọc và chỉnh sửa tệp trên hệ thống tệp cục bộ của họ. Người dùng phải cấp quyền trước khi trang có thể đọc hoặc ghi vào bất kỳ tệp cục bộ nào và quyền không được duy trì qua các phiên.

Bạn không nên sử dụng WebSQL và việc sử dụng hiện tại nên được chuyển sang IndexedDB. Hỗ trợ đã bị xoá khỏi hầu hết các kênh trình duyệt. W3C ngừng duy trì thông số kỹ thuật Web SQL vào năm 2010, và không có kế hoạch cập nhật thêm.

Bạn không nên sử dụng Bộ nhớ đệm của ứng dụng và nên sử dụng mức sử dụng hiện tại đã chuyển sang trình chạy dịch vụ và Cache API. Đã không dùng nữa và hỗ trợ sẽ bị loại bỏ khỏi các trình duyệt trong tương lai.

Tôi có thể lưu trữ bao nhiêu tiền?

Tóm lại là rất nhiều, ít nhất là vài trăm megabyte và có khả năng hàng trăm gigabyte trở lên. Triển khai trình duyệt sẽ khác nhau, nhưng số lượng bộ nhớ có sẵn thường dựa trên dung lượng bộ nhớ có sẵn trên thiết bị.

  • Chrome cho phép trình duyệt sử dụng tới 80% tổng dung lượng ổ đĩa. Nguồn gốc có thể lên tới 60% tổng dung lượng ổ đĩa. Bạn có thể sử dụng StorageManager API để xác định hạn mức tối đa hiện có. Khác dựa trên Chromium các trình duyệt có thể khác nhau.
    • Ở chế độ ẩn danh, Chrome sẽ giảm mức bộ nhớ mà một nguồn gốc có thể sử dụng chiếm khoảng 5% tổng dung lượng ổ đĩa.
    • Nếu người dùng đã bật tuỳ chọn "Xoá cookie và dữ liệu trang web khi bạn đóng tất cả cửa sổ" trong Chrome, hạn mức bộ nhớ sẽ giảm đáng kể xuống còn tối đa khoảng 300 MB.
    • Xem PR #3896 để biết chi tiết về việc triển khai Chrome.
  • Internet Explorer 10 trở lên có thể lưu trữ lên đến 250MB và sẽ nhắc người dùng khi đã sử dụng hơn 10 MB.
  • Firefox cho phép trình duyệt sử dụng tối đa 50% dung lượng ổ đĩa trống. Một eTLD+1 nhóm (ví dụ: example.com, www.example.comfoo.bar.example.com) có thể sử dụng tối đa 2 GB. Bạn có thể sử dụng API StorageManager để xác định mức dung lượng vẫn còn sẵn có.
  • Safari (cả máy tính và thiết bị di động) có vẻ cho phép khoảng 1GB. Khi giới hạn đã đạt đến giới hạn 200MB, Safari sẽ nhắc người dùng, tăng giới hạn lên 200MB tăng lên. Tôi không tìm thấy tài liệu chính thức nào về vấn đề này.
    • Nếu một ứng dụng web tiến bộ (PWA) được thêm vào màn hình chính trong Safari dành cho thiết bị di động, thì có vẻ như PWA này tạo một vùng chứa lưu trữ mới và không có nội dung nào được chia sẻ giữa PWA và Safari trên thiết bị di động. Sau khi đạt đến hạn mức cho một PWA đã cài đặt, có vẻ không phải là cách nào để yêu cầu thêm dung lượng.

Trước đây, nếu một trang web vượt quá ngưỡng dữ liệu được lưu trữ nhất định, thì trình duyệt sẽ nhắc người dùng cấp quyền sử dụng nhiều dữ liệu hơn. Cho ví dụ: nếu máy chủ gốc sử dụng hơn 50 MB, trình duyệt sẽ nhắc người dùng để cho phép bộ nhớ lưu trữ lên đến 100 MB, sau đó yêu cầu lại với mức tăng 50 MB.

Ngày nay, hầu hết các trình duyệt hiện đại sẽ không nhắc người dùng và sẽ cho phép một trang web để sử dụng hết hạn mức được phân bổ. Có vẻ như Safari, lời nhắc khi vượt quá hạn mức bộ nhớ và yêu cầu quyền tăng hạn mức được phân bổ. Nếu nguồn gốc cố gắng sử dụng nhiều hơn hạn mức được phân bổ, cố gắng ghi dữ liệu hơn nữa sẽ không thành công.

Làm cách nào để kiểm tra dung lượng lưu trữ còn trống?

Trong nhiều trình duyệt, bạn có thể sử dụng API StorageManager để xác định mức dung lượng lưu trữ có sẵn cho máy chủ gốc và mức dung lượng lưu trữ mà máy chủ đang sử dụng. Nó báo cáo tổng số số byte được IndexedDB và Cache API sử dụng đồng thời có thể thực hiện việc này để tính toán dung lượng lưu trữ ước tính còn lại.

if (navigator.storage && navigator.storage.estimate) {
  const quota = await navigator.storage.estimate();
  // quota.usage -> Number of bytes used.
  // quota.quota -> Maximum number of bytes available.
  const percentageUsed = (quota.usage / quota.quota) * 100;
  console.log(`You've used ${percentageUsed}% of the available storage.`);
  const remaining = quota.quota - quota.usage;
  console.log(`You can write up to ${remaining} more bytes.`);
}

StorageManager chưa được implemented trong tất cả các trình duyệt, vì vậy, bạn phải phát hiện trước khi sử dụng. Ngay cả khi có sẵn, bạn phải vẫn gặp lỗi vượt hạn mức (xem bên dưới). Trong một số trường hợp, có thể hạn mức hiện có để vượt quá dung lượng bộ nhớ thực tế có sẵn.

Kiểm tra

Trong quá trình phát triển, bạn có thể sử dụng Công cụ cho nhà phát triển của trình duyệt để kiểm tra các loại bộ nhớ khác nhau và dễ dàng xoá tất cả dữ liệu đã lưu trữ.

Chrome 88 đã bổ sung một tính năng mới cho phép bạn ghi đè bộ nhớ của trang web hạn mức trong Ngăn bộ nhớ. Tính năng này cho phép bạn mô phỏng các thiết bị khác nhau và kiểm thử hành vi của các ứng dụng khi ổ đĩa sắp hết trong trường hợp cụ thể. Chuyển đến Application (Ứng dụng), sau đó chọn Storage (Bộ nhớ), bật Hộp đánh dấu Mô phỏng hạn mức bộ nhớ tuỳ chỉnh rồi nhập bất kỳ số hợp lệ nào vào mô phỏng hạn mức bộ nhớ.

Ngăn lưu trữ trong Công cụ cho nhà phát triển.

Trong quá trình viết bài viết này, tôi đã viết một công cụ đơn giản để hãy cố gắng sử dụng nhanh nhất có thể nhiều dung lượng lưu trữ nhất có thể. Đây là một cách nhanh chóng và dễ dàng để thử nghiệm với các cơ chế lưu trữ khác nhau và xem điều gì sẽ xảy ra khi bạn sử dụng hết hạn mức.

Làm thế nào để xử lý việc vượt quá hạn mức?

Bạn nên làm gì khi vượt quá hạn mức? Quan trọng nhất là bạn nên luôn phát hiện và xử lý lỗi ghi, cho dù đó là lỗi QuotaExceededError hay khác. Sau đó, tuỳ thuộc vào thiết kế của ứng dụng, hãy quyết định cách xử lý. Ví dụ: xoá nội dung đã lâu bạn không truy cập, hãy xoá dựa trên kích thước hoặc cung cấp cho người dùng cách thức để chọn dữ liệu họ muốn xoá.

Cả IndexedDB và Cache API đều gửi một DOMError có tên QuotaExceededError khi bạn vượt quá hạn mức hiện có.

IndexedDB

Nếu nguồn gốc đã vượt quá hạn mức, các nỗ lực ghi vào IndexedDB sẽ không thành công. Trình xử lý onabort() của giao dịch sẽ được gọi, truyền một sự kiện. Sự kiện này sẽ bao gồm một DOMException trong thuộc tính lỗi. Đang kiểm tra lỗi name sẽ trả về QuotaExceededError.

const transaction = idb.transaction(['entries'], 'readwrite');
transaction.onabort = function(event) {
  const error = event.target.error; // DOMException
  if (error.name == 'QuotaExceededError') {
    // Fallback code goes here
  }
};

API Bộ nhớ đệm

Nếu máy chủ gốc đã vượt quá hạn mức, hãy cố gắng ghi vào Cache API sẽ từ chối bằng QuotaExceededError DOMException.

try {
  const cache = await caches.open('my-cache');
  await cache.add(new Request('/sample1.jpg'));
} catch (err) {
  if (error.name === 'QuotaExceededError') {
    // Fallback code goes here
  }
}

Quyết định trục xuất hoạt động như thế nào?

Bộ nhớ web được phân thành hai nhóm, "Nỗ lực tốt nhất" và "Sự bền vững". Nếu có thể, trình duyệt có thể xoá bộ nhớ mà không cần làm gián đoạn người dùng, nhưng kém bền vững hơn đối với dữ liệu lâu dài hoặc quan trọng. Bộ nhớ liên tục không tự động bị xoá khi sắp hết bộ nhớ. Người dùng cần xóa bộ nhớ này theo cách thủ công (thông qua cài đặt trình duyệt).

Theo mặc định, dữ liệu của trang web (bao gồm IndexedDB, Cache API, v.v.) rơi vào danh mục nỗ lực cao nhất, nghĩa là trừ phi một trang web đã yêu cầu lưu trữ liên tục, thì trình duyệt có thể xoá dữ liệu trang web theo ý mình, ví dụ như khi thiết bị sắp hết bộ nhớ.

Chính sách trục xuất đối với nỗ lực cao nhất là:

  • Các trình duyệt dựa trên Chromium sẽ bắt đầu xoá dữ liệu khi trình duyệt hết thời gian, xoá tất cả dữ liệu trang web khỏi nguồn ít được sử dụng gần đây trước tiên, tiếp theo, cho đến khi trình duyệt không còn vượt quá giới hạn.
  • Internet Explorer 10+ sẽ không loại bỏ dữ liệu nhưng sẽ ngăn nguồn gốc viết thêm bất kỳ nội dung nào nữa.
  • Firefox sẽ bắt đầu xoá dữ liệu khi dung lượng ổ đĩa trống đã đầy, xoá tất cả dữ liệu trang web khỏi nguồn ít được sử dụng gần đây nhất trước, sau đó tiếp theo, cho đến khi trình duyệt không còn vượt quá giới hạn.
  • Trước đây, Safari không loại bỏ dữ liệu, nhưng gần đây đã triển khai một giới hạn bảy ngày đối với tất cả bộ nhớ có thể ghi (xem bên dưới).

Bắt đầu từ iOS và iPadOS 13.4 và Safari 13.1 trên macOS, có một giới hạn 7 ngày đối với tất cả bộ nhớ có thể ghi của tập lệnh, bao gồm IndexedDB, dịch vụ đăng ký trình thực thi và Cache API. Điều này có nghĩa là Safari sẽ loại bỏ tất cả nội dung từ bộ nhớ đệm sau 7 ngày sử dụng Safari nếu người dùng không tương tác với trang web. Chính sách loại bỏ này không áp dụng cho các thiết bị đã cài đặt PWA đã được thêm vào màn hình chính. Xem Chặn cookie của bên thứ ba đầy đủ và nhiều tính năng khác trên WebKit để biết toàn bộ thông tin chi tiết.

Thêm: Tại sao nên sử dụng trình bao bọc cho IndexedDB

IndexedDB là API cấp thấp yêu cầu thiết lập đáng kể trước khi sử dụng, và phương thức này có thể đặc biệt khó khăn cho việc lưu trữ dữ liệu đơn giản. Không giống như các phiên bản hiện đại nhất dựa trên lời hứa, dựa trên sự kiện. Trình bao bọc lời hứa như idb cho IndexedDB ẩn một số tính năng mạnh mẽ nhưng nhiều tính năng khác quan trọng là ẩn các bộ máy phức tạp (ví dụ: các giao dịch, phiên bản giản đồ) đi kèm với thư viện IndexedDB.

Kết luận

Đã qua cái thời hạn chế bộ nhớ và nhắc người dùng lưu trữ nhiều hơn nhiều dữ liệu hơn. Các trang web có thể lưu trữ hiệu quả tất cả tài nguyên và dữ liệu mà chúng cần chạy. Bằng cách sử dụng API StorageManager, bạn có thể xác định số tiền bạn có thể sử dụng và mức bạn đã sử dụng. Và bằng bộ nhớ bền vững, trừ phi người dùng xoá bộ nhớ này, bạn có thể giúp bảo vệ tài khoản khỏi bị giải phóng.

Tài nguyên khác

Cảm ơn bạn!

Đặc biệt cảm ơn Jarryd Goodman, Phil Walton, Eiji Kitamura, Daniel Murphy, Darwin Huang, Josh Bell, Marijn Kruisselbrink và Victor Costan đã đánh giá bài viết này. Nhờ có Eiji Kitamura, Addy Osmani và Marc Cohen đã viết kịch bản các bài viết gốc làm cơ sở. Eiji đã viết một công cụ hữu ích có tên là Người lạm dụng bộ nhớ trình duyệt, rất hữu ích trong việc xác thực hành vi hiện tại. Nhờ vậy, bạn có thể lưu trữ nhiều dữ liệu nhất có thể và xem giới hạn bộ nhớ trên trình duyệt của bạn. Nhờ Francois Beaufort , người đã đào sâu vào Safari để tìm hiểu giới hạn bộ nhớ.

Hình ảnh chính là của Guillaume Bolduc trên Không hiển thị ứng dụng.