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

Jeff Posnick
J Jeff Posnick

tl;dr

Chrome 61, với nhiều trình duyệt hơn trong tương lai, giờ đây sẽ cho biết mức bộ nhớ ước tính 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.`);
  });
}

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

Khi bạn suy nghĩ về nhu cầu lưu trữ của một ứng dụng web hiện đại, điều này giúp chia nội dung đượ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, 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ớ 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 sử dụng chúng sau này để 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 của ứng dụng web, như thư viện Workbox (Hộp làm việc) mới hoặc sw-precache cũ, có thể hoàn toàn tự động hoá 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 còn lại thì sao? Đây là các 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. Chẳng hạn như 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 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. 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 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ố thông tin về 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ợ hình thức xem xét nội dung này thông qua các giao diện có tiền tố, chẳng hạn như window.webkitStorageInfo đã quá cũ (và không được dùng nữa) và navigator.webkitTemporaryStorage đã cũ nhưng vẫn không chuẩn mực. Mặc dù những 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 whatWG Storage Standard nhập hình ảnh.

Trong tương lai: navigator.storage

Trong khuôn khổ công việc liên quan đến Storage Living Standard, một số API hữu ích đã được đưa vào giao diện StorageManager (hiển thị với 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ó sẵn 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 miễn bộ nhớ của ứng dụng 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(). Phương thức này là giải pháp 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 hứa hẹn phù hợp với các API không đồng bộ hiện đại khác. Lời hứa rằng estimate() trả về sẽ được 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 có thể được lưu trữ theo nguồn gốc hiện tại. (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ữ — chẳng hạn như IndexedDB hoặc Cache Storage API — dữ liệu đủ lớn để truyền một nguồn gốc cụ thể vượt quá hạn mức hiện có, thì yêu cầu sẽ không thành công với trường hợp ngoại lệ QuotaExceededError.

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

Cách chính xác bạn sử dụng estimate() 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 để người dùng biết mức dung lượng đang sử dụng sau khi mỗi hoạt động bộ nhớ hoàn tất. Tốt nhất là bạn nên cung cấp một giao diện cho phép người dùng xoá dữ liệu không còn cần thiết theo cách thủ công. Bạn có thể viết mã 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 chính xác đến mức nào?

Thật khó để bỏ lỡ một thực tế là dữ liệu bạn nhận được qua hàm này chỉ là thông tin ướ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ả giá trị usagequota đều không ổn định, vì vậy, bạn nên tính đến những điều sau:

  • usage cho biết 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, do đó có thể bị ảnh hưởng bởi 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 các bản ghi"tombstone" có thể được tạo tạm thời sau khi xoá. Để tránh rò rỉ thông tin về kích thước chính xác, các tài nguyên mờ gốc, được lưu cục bộ có thể đóng góp thêm số 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ị này phụ thuộc vào một số yếu tố không đổi như dung lượng bộ nhớ tổng thể, nhưng cũng một số yếu tố dễ biến động, bao gồm cả dung lượng bộ nhớ hiện chưa được 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, mức 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.

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

estimate() được bật theo mặc định kể từ Chrome 61. Firefox đang thử nghiệm 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 dom.storageManager.enabled để kiểm thử.

Khi làm việc với chức năng chưa được hỗ trợ trong một số trình duyệt, bạn phải dùng tính năng 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 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});
}