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

Tóm tắt

Chrome 61, cùng với nhiều trình duyệt khác sắp ra mắt, hiện hiển thị số liệu ước tính về dung lượng lưu trữ mà một ứng dụng web đang sử dụng và dung lượng 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.`);
  });
}

Ứng dụng web hiện đại và lưu trữ dữ liệu

Khi bạn nghĩ về nhu cầu lưu trữ của một ứng dụng web hiện đại, bạn nên phân chia những gì được lưu trữ thành hai 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 cho hoạt động tương tác có ý nghĩa của người dùng sau khi ứng dụng được tải.

Loại dữ liệu đầu tiên (những dữ liệu cần thiết để tải ứng dụng web) 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 đó, sau đó sử dụng các tài nguyên đó để tải nhanh ứng dụng web của bạn, lý tưởng 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 ứng dụng web, chẳng hạn như thư viện Workbox 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.)

Nhưng còn loại dữ liệu khác 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 có thể muốn lưu một hoặc nhiều bản sao cục bộ 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 ngoại tuyến, thì việc lưu tệp âm thanh hoặc video trên máy sẽ là một tính năng quan trọng. Mọi ứng dụng web có thể được cá nhân hoá đều cần lưu một số loại thông tin trạng thái. Làm cách nào để biết 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

Trước đây, các trình duyệt đã hỗ trợ loại hoạt động tự xem xét 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 còn được dùng nữa) và navigator.webkitTemporaryStorage không quá cũ nhưng vẫn không theo tiêu 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 như các tiêu chuẩn web.

Đó là lúc Tiêu chuẩn lưu trữ WHATWG xuất hiện.

Tương lai: navigator.storage

Trong quá trình tiếp tục triển khai Storage Living Standard, một số API hữu ích đã được đưa vào giao diện StorageManager. Giao diện này được hiển thị cho trình duyệt dưới dạng navigator.storage. Giống như nhiều API web mới hơn, 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 localhost).

Năm ngoái, chúng tôi đã ra mắt phương thức navigator.storage.persist(). Phương thức này 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 khỏi việc dọn dẹp tự động.

Phương thức này hiện được kết hợp với phương thức navigator.storage.estimate(), đóng vai trò là phương thức 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 mà estimate() 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 được sử dụng và quota, đại diện cho số byte tối đa mà nguồn gốc hiện tại có thể lưu trữ. (Giống như mọi thứ khác liên quan đến bộ nhớ, hạn mức được áp dụng trên toàn bộ nguồn gốc.)

Nếu một ứng dụng web cố gắng lưu trữ (ví dụ: sử 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ới ngoại lệ QuotaExceededError.

Ước tính bộ nhớ trong thực tế

Cách bạn sử dụng estimate() chính xác sẽ 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 thành phần điều khiển trong giao diện để cho người dùng biết dung lượng đang được sử dụng sau mỗi thao tác lưu trữ. Sau đó, bạn nên cung cấp một giao diện cho phép người dùng dọn dẹp dữ liệu không cần thiết theo cách thủ công. Bạn có thể viết mã theo các dòng sau:

// 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;
  }
}

Mức ước tính này chính xác đến mức nào?

Bạn khó có thể bỏ qua thực tế là dữ liệu mà bạn nhận được từ hàm này chỉ là một ước tính về không gian mà một nguồn gốc đang sử dụng. Tên hàm đó ngay trong tên hàm! Cả giá trị usagequota đều không ổn định, vì vậy, bạn nên cân nhắc những điều sau:

  • usage phản ánh số 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. Điều này 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ổ có kích thước cố định có thể bao gồm không gian không sử dụng và sự hiện diện của bản ghi"đá mộ" có thể được tạo tạm thời sau khi xoá. Để ngăn chặn việc rò rỉ thông tin kích thước chính xác, các tài nguyên mờ, đa nguồn gốc được lưu cục bộ có thể đóng góp thêm các byte đệm vào giá trị usage tổng thể.
  • quota phản ánh dung lượng hiện được đặt trước cho một nguồn gốc. Giá trị này phụ thuộc vào một số yếu tố không đổi như tổng dung lượng bộ nhớ, nhưng cũng 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 không sử dụng. 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 tuỳ chọn dom.storageManager.enabled để kiểm thử tuỳ chọn này.

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

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});
}