Ước tính dung lượng lưu trữ còn trống

tl;dr

Chrome 61 (với nhiều trình duyệt hơn sau này) nay sẽ hiển thị thông tin ước tính về dung lượng bộ nhớ mà một ứng dụng web đang sử dụng và mức bộ nhớ còn trống thông qua:

if ('storage' in navigator && 'estimate' in navigator.storage) {
  navigator.storage.estimate().then(({usage, quota}) => {
    console.log(`Using ${usage} out of ${quota} bytes.`);
  });
}

Bộ nhớ dữ liệu và ứng dụng web hiện đại

Khi xem xét nhu cầu lưu trữ của một ứng dụng web hiện đại, bạn cần chia những nội dung đang được lưu trữ thành 2 danh mục: dữ liệu cốt lõi cần thiết để tải ứng dụng web và dữ liệu cần thiết để người dùng tương tác có ý nghĩa sau khi tải ứng dụng.

Loại dữ liệu đầu tiên (những gì cần thiết để tải ứng dụng web của bạn) bao gồm HTML, JavaScript, CSS và có thể là một số hình ảnh. Trình chạy dịch vụ, cùng với API Bộ nhớ đệm, cung cấp cơ sở hạ tầng cần thiết để lưu các tài nguyên cốt lõi đó rồi sau đó sử dụng chúng để nhanh chóng tải ứng dụng web của bạn, tốt nhất là bỏ qua hoàn toàn mạng. (Các công cụ tích hợp với quy trình xây dựng của ứng dụng web, chẳng hạn như thư viện Hộp công việc mới hoặc sw-precache cũ, có thể tự động hoá hoàn toàn quy trình lưu trữ, cập nhật và sử dụng loại dữ liệu này.)

Còn loại dữ liệu kia thì sao? Đây là những tài nguyên không cần thiết để tải ứng dụng web, nhưng có thể đóng vai trò quan trọng trong trải nghiệm tổng thể của người dùng. Ví dụ: nếu đang viết một ứng dụng web chỉnh sửa hình ảnh, bạn nên lưu một hoặc nhiều bản sao trên máy của hình ảnh, cho phép người dùng chuyển đổi giữa các bản sửa đổi và huỷ công việc của họ. Hoặc nếu bạn đang phát triển trải nghiệm phát nội dung nghe nhìn khi không có mạng, thì việc lưu các tệp âm thanh hoặc video trên thiết bị là một tính năng quan trọng. Mọi ứng dụng web có thể được cá nhân hoá sẽ cần lưu một số thông tin trạng thái. Làm cách nào để bạn biết có bao nhiêu dung lượng còn trống cho loại bộ nhớ thời gian chạy này và điều gì sẽ xảy ra khi bạn hết dung lượng?

Trước đây: window.webkitStorageInfonavigator.webkitTemporaryStorage

Các trình duyệt trước đây đã hỗ trợ loại nội dung truy vấn này thông qua các giao diện có tiền tố, chẳng hạn như window.webkitStorageInfo rất cũ (và không dùng nữa) và navigator.webkitTemporaryStorage tuy rất cũ nhưng vẫn không chuẩn. Mặc dù các giao diện này cung cấp thông tin hữu ích, nhưng chúng không có tương lai làm tiêu chuẩn web.

Đó là nơi Tiêu chuẩn lưu trữ thứ hạng thứ hạng nhập hình ảnh.

Tương lai: navigator.storage

Trong quá trình triển khai Storage Living Standard, một số API hữu ích đã đưa API này vào giao diện StorageManager, hiển thị với các trình duyệt dưới dạng navigator.storage. Giống như nhiều API web mới hơn khác, navigator.storage chỉ có trên các nguồn gốc bảo mật (được phân phát qua HTTPS hoặc máy chủ cục bộ).

Năm ngoái, chúng tôi đã ra mắt phương thức navigator.storage.persist(), cho phép ứng dụng web của bạn yêu cầu bộ nhớ của ứng dụng được miễn trừ khỏi tính năng tự động dọn dẹp.

Phương thức này hiện được kết hợp bằng phương thức navigator.storage.estimate(), đóng vai trò thay thế hiện đại cho navigator.webkitTemporaryStorage.queryUsageAndQuota(). estimate() trả về thông tin tương tự, nhưng hiển thị giao diện dựa trên lời hứa, phù hợp với các API không đồng bộ hiện đại khác. Lời hứa estimate() sẽ trả về sẽ phân giải bằng một đối tượng chứa hai thuộc tính: usage (đại diện cho số byte hiện đang sử dụng) và quota (đại diện cho số byte tối đa có thể lưu trữ theo nguồn gốc hiện tại). (Giống như mọi nội dung khác liên quan đến việc lưu trữ, hạn mức được áp dụng trên toàn bộ một nguồn gốc.)

Nếu một ứng dụng web cố gắng lưu trữ (chẳng hạn như dùng IndexedDB hoặc API Bộ nhớ đệm) – dữ liệu đủ lớn để đưa một nguồn gốc nhất định vượt quá hạn mức hiện có, thì yêu cầu đó sẽ không thành công và có ngoại lệ QuotaExceededError.

Thông tin ước tính về dung lượng lưu trữ trong thực tế

Việc bạn sử dụng estimate() chính xác phụ thuộc vào loại dữ liệu mà ứng dụng của bạn cần lưu trữ. Ví dụ: bạn có thể cập nhật một chế độ kiểm soát trong giao diện để cho người dùng biết dung lượng bộ nhớ sẽ dùng sau khi mỗi hoạt động lưu trữ hoàn tất. Sau đó, bạn nên cung cấp một giao diện cho phép người dùng tự xoá dữ liệu không còn cần thiết nữa. Bạn có thể viết mã dọc theo các dòng:

// For a primer on async/await, see
// https://developers.google.com/web/fundamentals/getting-started/primers/async-functions
async function storeDataAndUpdateUI(dataUrl) {
  // Pro-tip: The Cache Storage API is available outside of service workers!
  // See https://googlechrome.github.io/samples/service-worker/window-caches/
  const cache = await caches.open('data-cache');
  await cache.add(dataUrl);

  if ('storage' in navigator && 'estimate' in navigator.storage) {
    const {usage, quota} = await navigator.storage.estimate();
    const percentUsed = Math.round(usage / quota * 100);
    const usageInMib = Math.round(usage / (1024 * 1024));
    const quotaInMib = Math.round(quota / (1024 * 1024));

    const details = `${usageInMib} out of ${quotaInMib} MiB used (${percentUsed}%)`;

    // This assumes there's a <span id="storageEstimate"> or similar on the page.
    document.querySelector('#storageEstimate').innerText = details;
  }
}

Số liệu ước tính có chính xác không?

Thật khó để bỏ lỡ dữ liệu mà bạn nhận được từ hàm này chỉ là số liệu ước tính về không gian mà một nguồn gốc đang sử dụng. Nó nằm ngay trong tên hàm! Cả usagequota đều không hướng ổn định. Vì vậy, bạn nên tính đến những điều sau:

  • usage phản ánh số lượng byte mà một nguồn gốc nhất định đang sử dụng hiệu quả cho dữ liệu cùng nguồn gốc, sau đó có thể chịu ảnh hưởng của các kỹ thuật nén nội bộ, các khối phân bổ kích thước cố định có thể bao gồm dung lượng không sử dụng và sự hiện diện của bản ghi"tombstone" có thể được tạo tạm thời sau khi bị xoá. Để ngăn chặn việc rò rỉ thông tin về kích thước chính xác, các tài nguyên mờ trên nhiều nguồn gốc được lưu cục bộ có thể đóng góp thêm các byte khoảng đệm vào giá trị usage tổng thể.
  • quota phản ánh lượng không gian hiện được đặt trước cho một điểm khởi hành. Giá trị phụ thuộc vào một số yếu tố không đổi như tổng dung lượng bộ nhớ, ngoài ra còn phụ thuộc vào một số yếu tố có thể biến động, bao gồm cả dung lượng bộ nhớ hiện chưa dùng đến. Vì vậy, khi các ứng dụng khác trên thiết bị ghi hoặc xoá dữ liệu, dung lượng mà trình duyệt sẵn sàng dành cho nguồn gốc của ứng dụng web có thể sẽ thay đổi.

Hiện tại: phát hiện tính năng và dự phòng

estimate() được bật theo mặc định kể từ Chrome 61. Firefox đang thử nghiệm với navigator.storage, nhưng kể từ tháng 8 năm 2017, tính năng này không được bật theo mặc định. Bạn cần bật lựa chọn ưu tiên về dom.storageManager.enabled để kiểm thử lựa chọn này.

Khi làm việc với một chức năng chưa được hỗ trợ trên một số trình duyệt, bạn bắt buộc phải sử dụng tính năng phát hiện. Bạn có thể kết hợp tính năng phát hiện tính năng với một trình bao bọc dựa trên lời hứa ở đầu các phương thức navigator.webkitTemporaryStorage cũ để cung cấp một giao diện nhất quán dọc theo các dòng:

function storageEstimateWrapper() {
  if ('storage' in navigator && 'estimate' in navigator.storage) {
    // We've got the real thing! Return its response.
    return navigator.storage.estimate();
  }

  if ('webkitTemporaryStorage' in navigator &&
      'queryUsageAndQuota' in navigator.webkitTemporaryStorage) {
    // Return a promise-based wrapper that will follow the expected interface.
    return new Promise(function(resolve, reject) {
      navigator.webkitTemporaryStorage.queryUsageAndQuota(
        function(usage, quota) {resolve({usage: usage, quota: quota})},
        reject
      );
    });
  }

  // If we can't estimate the values, return a Promise that resolves with NaN.
  return Promise.resolve({usage: NaN, quota: NaN});
}