適合應用程式的高效能儲存空間: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 審查。

主頁橫幅圖片由 Unsplash 上的 Markus Spiske 提供。