適合應用程式的高效能儲存空間:Storage Foundation API

網路平台越來越常為開發人員提供所需工具,以便為網路平台建構經過微調的高效能應用程式。最值得注意的是,WebAssembly (Wasm) 為快速且強大的網頁應用程式開創了新契機,而 Emscripten 等技術則可讓開發人員在網路上重複使用經測試與測試的程式碼。開發人員在儲存空間方面必須具備相同的功能與靈活性,才能真正善用這股潛力。

這時 Storage Foundation API 就能派上用場。Storage Foundation API 是一個快速且不失調性的新儲存空間 API,可發掘眾所期盼的新網路應用實例,例如實作高效能資料庫,以及妥善管理大型暫存檔案。透過這種新介面,開發人員可以為網頁「使用自己的儲存空間」,減少網頁和平台專用程式碼之間的功能差距。

Storage Foundation API 的設計與非常基本的檔案系統類似,因此能夠提供通用、簡單且效能卓越的基本功能,讓開發人員能夠靈活運用這些基本功能來建構更高層級的元件。應用程式可以根據自身需求採用最佳工具,在可用性、效能和可靠性之間找到理想平衡。

為什麼網路需要其他 Storage API?

網路平台為開發人員提供多種儲存空間選項,每個選項都是專為特定用途所設計。

  • 其中某些選項只能儲存極少量資料,例如 Cookie,或是包含 sessionStoragelocalStorage 機制的 Web Storage API,因此有些選項不會與本提案重疊。
  • 基於 File and Directory Entry APIWebSQL 等各種原因,其他選項已遭淘汰。
  • File System Access API 有類似的 API 介面,但其用途是與用戶端的檔案系統互動,並提供可能不屬於來源,甚至瀏覽器擁有權的資料存取權。這種不同的重點會需要更嚴謹的安全性考量 以及效能的成本也較高
  • IndexedDB API 可做為 Storage Foundation API 中某些用途的後端使用。例如,emscripten 包含 IDBFS,這個以索引資料庫為基礎的永久檔案系統。不過,由於 IndexedDB 基本上是鍵/值儲存庫,因此會有重大的效能限制。再者,直接存取檔案的子區段比起 IndexedDB 來得更加困難且速度變慢。
  • 最後,CacheStorage 介面受到廣泛支援,且已針對儲存網頁應用程式資源等大型資料進行調整,但這些值無法變更。

Storage Foundation API 允許儲存在應用程式來源中定義的可變動大型檔案,以關閉先前儲存空間選項的所有缺口。

Storage Foundation API 的建議用途

以下列舉可能使用此 API 的網站:

  • 可處理大量影片、音訊或圖片資料的效率提升或創意應用程式,這類應用程式可以將區隔卸載至磁碟,而非將區隔保存在記憶體中。
  • 這類應用程式仰賴透過 Wasm 存取的永久檔案系統,且需要的效能高於 IDBFS 保證的效能。

什麼是 Storage Foundation API?

API 包含兩個主要部分:

  • 檔案系統呼叫,提供與檔案和檔案路徑互動的基本功能。
  • 檔案控點:提供現有檔案的讀取和寫入權限。

檔案系統呼叫

Storage Foundation API 提供位於 window 物件上的新物件 storageFoundation,其中包含數個函式:

  • storageFoundation.open(name):開啟具有指定名稱的檔案 (如果有的話),否則建立新檔案。傳回以開啟檔案解析的承諾。
  • storageFoundation.delete(name):移除具有指定名稱的檔案。傳回會在檔案刪除時解決的承諾。
  • storageFoundation.rename(oldName, newName):將檔案從舊名稱重新命名為新名稱。傳回重新命名檔案後可解析的承諾。
  • storageFoundation.getAll():傳回以所有現有檔案名稱陣列解析的承諾。
  • storageFoundation.requestCapacity(requestedCapacity):要求目前執行環境的用量資料容量 (以位元組為單位)。傳回承諾使用剩餘容量的承諾。
  • storageFoundation.releaseCapacity(toBeReleasedCapacity):從目前的執行環境釋出指定位元組數,並傳回以剩餘容量解析的承諾。
  • storageFoundation.getRemainingCapacity():傳回以目前執行環境可用容量來解析的承諾。

檔案控制代碼

處理檔案的作業是透過下列函式進行:

  • NativeIOFile.close():關閉檔案,並傳回會在作業完成時解析的承諾。
  • NativeIOFile.flush():同步處理 (也就是清除) 檔案記憶體與儲存裝置中的狀態,並傳回在作業完成時解析的承諾。
  • NativeIOFile.getLength():傳回以檔案長度解析的承諾,以位元組為單位。
  • NativeIOFile.setLength(length):設定檔案長度 (以位元組為單位),並傳回在作業完成時解析的承諾。如果新的長度小於目前長度,則會從檔案結尾開始移除位元組。否則,系統會以零值位元組的形式擴充此檔案。
  • NativeIOFile.read(buffer, offset):透過緩衝區 (也就是傳輸指定緩衝區的結果) 讀取指定偏移的檔案內容,然後此緩衝區之後會留下單獨卸離。傳回 NativeIOReadResult,其中包含已轉移的緩衝區,以及成功讀取的位元組數。

    NativeIOReadResult 是一個物件,由兩個項目組成:

    • bufferArrayBufferView,也就是將傳遞至 read() 的緩衝區轉移的結果。類型和長度與來源緩衝區相同。
    • readBytes:成功讀取到 buffer 的位元組數。如果發生錯誤,或讀取範圍跨越檔案結尾時,這個數量可能小於緩衝區空間。如果讀取範圍超出檔案結尾,系統會將此值設為零。
  • NativeIOFile.write(buffer, offset):在指定的偏移處將指定緩衝區的內容寫入檔案。這個緩衝區會在寫入任何資料之前傳輸,因此會將其卸離。傳回 NativeIOWriteResult,其中包含已轉移的緩衝區,以及成功寫入的位元組數。如果寫入範圍超過寫入範圍,系統會擴充檔案。

    NativeIOWriteResult 是一個物件,由兩個項目組成:

    • bufferArrayBufferView,也就是將傳遞至 write() 的緩衝區轉移的結果。其類型和長度與來源緩衝區相同。
    • writtenBytes:成功寫入 buffer 的位元組數。如果發生錯誤,這個值可能會小於緩衝區空間。

完整範例

為了更清楚說明上述概念,以下兩個完整的範例將逐步說明 Storage 基礎檔案生命週期的不同階段。

開啟、書寫、閱讀、關閉

// Open a file (creating it if needed).
const file = await storageFoundation.open('test_file');
try {
  // Request 100 bytes of capacity for this context.
  await storageFoundation.requestCapacity(100);

  const writeBuffer = new Uint8Array([64, 65, 66]);
  // Write the buffer at offset 0. After this operation, `result.buffer`
  // contains the transferred buffer and `result.writtenBytes` is 3,
  // the number of bytes written. `writeBuffer` is left detached.
  let result = await file.write(writeBuffer, 0);

  const readBuffer = new Uint8Array(3);
  // Read at offset 1. `result.buffer` contains the transferred buffer,
  // `result.readBytes` is 2, the number of bytes read. `readBuffer` is left
  // detached.
  result = await file.read(readBuffer, 1);
  // `Uint8Array(3) [65, 66, 0]`
  console.log(result.buffer);
} finally {
  file.close();
}

開啟、列出、刪除

// Open three different files (creating them if needed).
await storageFoundation.open('sunrise');
await storageFoundation.open('noon');
await storageFoundation.open('sunset');
// List all existing files.
// `["sunset", "sunrise", "noon"]`
await storageFoundation.getAll();
// Delete one of the three files.
await storageFoundation.delete('noon');
// List all remaining existing files.
// `["sunrise", "noon"]`
await storageFoundation.getAll();

操作示範

您可以在下方嵌入內容中,試用 Storage Foundation API 示範。建立、重新命名、寫入及讀取檔案,並在進行變更時查看要求更新的可用容量。您可以在 Glitch 上找到示範的原始碼

安全性和權限

Chromium 團隊根據控管強大的 Web Platform 功能存取權中定義的核心原則 (包括使用者控管權、資訊公開和人體工學),設計並實作 Storage Foundation API。

與網路上其他新型儲存空間 API 的模式相同,Storage Foundation API 的存取權會受到限制,這表示來源只能存取自行建立的資料。此外,它也只適用於安全內容。

使用者控制項

系統會使用儲存空間配額來分配磁碟空間的存取權,並避免濫用情形。必須先要求要佔用的記憶體如同其他 Storage API,使用者可以透過瀏覽器清理 Storage Foundation API 所佔用的空間。

實用連結

特別銘謝

Storage Foundation API 是由 Emanuel KrivoyRichard Stotz 指定與實作。這篇文章是由 Pete LePageJoe Medley 審查。

透過 Markus Spiske 存取 Unsplash 上的主頁橫幅。