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

網頁平台提供的工具越來越多,開發人員可以利用這些工具,為網頁建構精密調校的高效能應用程式。最值得一提的是,WebAssembly (Wasm) 為開發人員開啟了快速且功能強大的網路應用程式大門,而Emscripten 等技術現在也允許開發人員在網路上重複使用經過驗證的程式碼。為了充分發揮這項潛力,開發人員必須在儲存空間方面擁有相同的效能和彈性。

這就是 Storage Foundation API 的用途。Storage Foundation API 是全新的快速且不具意見的儲存空間 API,可解鎖許多網頁新用途,例如實作效能良好的資料庫,以及妥善管理大型暫存檔案。有了這個全新介面,開發人員就能在網頁中「自備儲存空間」,縮小網頁和特定平台程式碼之間的功能差距。

Storage Foundation API 的設計類似於非常基本的檔案系統,因此可提供一般、簡單且效能良好的原始元素,讓開發人員靈活地建構高階元件。應用程式可以根據需求使用最合適的工具,在可用性、效能和可靠性之間取得平衡。

為什麼網頁需要另一個儲存空間 API?

網頁平台為開發人員提供多種儲存空間選項,每個選項都以特定用途為設計考量。

  • 其中有些選項顯然與這項提案無關,因為它們只允許儲存極少的資料,例如 Cookie,或是由 sessionStoragelocalStorage 機制組成的 Web Storage API
  • 其他選項已因各種原因而淘汰,例如 File and Directory Entries APIWebSQL
  • File System Access API 具有類似的 API 介面,但其用途是與用戶端的檔案系統介接,並提供對來源或瀏覽器擁有權以外的資料存取權。這類不同的重點會帶來更嚴格的安全考量和更高的效能成本。
  • IndexedDB API 可用於部分 Storage Foundation API 用途的後端。舉例來說,Emscripten 包含 IDBFS,這是以 IndexedDB 為基礎的持續性檔案系統。不過,由於 IndexedDB 基本上是鍵/值儲存庫,因此成效會受到重大限制。此外,在 IndexedDB 中直接存取檔案的子區段更是難上加難,速度也更慢。
  • 最後,CacheStorage 介面廣泛支援,並經過調整,可用於儲存大型資料 (例如網頁應用程式資源),但值無法變更。

Storage Foundation API 可讓應用程式原點定義的變動大型檔案以高效的方式儲存,藉此填補先前儲存空間選項的所有缺口。

Storage Foundation API 的建議用途

以下是可能會使用這個 API 的網站:

  • 以大量影片、音訊或圖片資料運作的生產力或創意應用程式。這類應用程式可以將區段卸載至磁碟,而非保留在記憶體中。
  • 應用程式會依賴可從 Wasm 存取的永久檔案系統,且需要的效能高於 IDBFS 可保證的效能。

什麼是 Storage Foundation API?

API 包含兩個主要部分:

  • 檔案系統呼叫:提供與檔案和檔案路徑互動的基礎功能。
  • 檔案句柄:提供現有檔案的讀取和寫入存取權。

檔案系統呼叫

Storage Foundation API 會引入新的物件 storageFoundation,該物件位於 window 物件上,並包含多項功能:

  • 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 Foundation 檔案生命週期中的不同階段。

開啟、寫入、讀取、關閉

// 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 團隊根據「控管強大網頁平台功能的存取權」一文中定義的核心原則,設計並實作 Storage Foundation API,包括使用者控管、資訊公開和人因工程。

與網站上其他新式儲存空間 API 相同,Storage Foundation API 的存取權受限於來源,也就是說,來源只能存取自行建立的資料。且僅限於安全的內容。

使用者控制項

儲存空間配額可用於分配磁碟空間存取權,並防止濫用行為。您必須先要求要佔用的記憶體。如同其他儲存空間 API,使用者可以透過瀏覽器清除 Storage Foundation API 占用的空間。

實用連結

特別銘謝

Emanuel KrivoyRichard Stotz 指定並實作了 Storage Foundation API。本文由 Pete LePageJoe Medley 審查。

主頁橫幅圖片由 Markus Spiske 提供,取自 Unsplash