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

網路平台日益增加,為開發人員提供所需工具,協助他們建構完善的網路效能應用程式。最值得注意的是,WebAssembly (Wasm) 已開放應用程式快速打造強大網頁應用程式,而 Emscripten 等技術則可讓開發人員重複使用網路上重複使用且經過測試的程式碼。如要真正發揮這項潛力,開發人員在儲存空間方面,必須具有相同的能力和彈性。

這時 Storage Foundation API 就能派上用場。Storage Foundation API 是快速且無所不包的全新 Storage API,可用於導入眾所期盼的新網路用途,例如實作高效能資料庫,以及妥善管理大型的暫存檔案。透過這個新介面,開發人員可以「自備儲存空間」至網路,減少網頁和平台專屬程式碼之間的功能差距。

Storage Foundation API 的設計與非常基本的檔案系統相似,因此提供一般、簡單且高效能的基本基元,為開發人員提供建構更高層級元件的靈活性。應用程式可以根據自身需求,利用最合適的工具,在可用性、效能和可靠性之間取得適當平衡。

為什麼網路需要其他儲存 API?

網路平台為開發人員提供多種儲存空間選項,每個選項都是考量特定用途建構而成。

  • 其中有些選項只允許儲存極少量的資料,例如 Cookie,或包含 sessionStoragelocalStorage 機制的 Web Storage API,因此沒有與此提案重疊,因此沒有明顯重疊。
  • 其他選項已淘汰,例如 File 和 Directory Entries APIWebSQL
  • File System Access API 的 API 介面類似,但用途是與用戶端的檔案系統介面互動,並提供可能位於來源外部,甚至是瀏覽器擁有權的資料存取權。這樣的不同關注度會更加嚴格,且效能成本也提高。
  • IndexedDB API 可做為 Storage Foundation API 部分用途的後端使用。例如,Escripten 包含 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):開啟指定名稱的檔案 (如果有的話),然後建立新檔案。傳回以開啟檔案解析的 promise。
  • storageFoundation.delete(name):移除具有指定名稱的檔案。傳回刪除檔案時可解決的承諾。
  • storageFoundation.rename(oldName, newName):以不可分割的形式,將檔案從舊名稱重新命名為新名稱。傳回在檔案重新命名後解析的 promise。
  • storageFoundation.getAll():傳回使用所有現有檔案名稱陣列解析的 promise。
  • 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 的位元組數量。如果發生錯誤,或是讀取範圍超過檔案結尾,這個值可能會小於緩衝區大小。如果讀取範圍超過檔案結尾,則會設為 0。
  • 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。

Storage Foundation API 與網路上其他現代化 Storage API 的模式相同,因此 Storage Foundation API 的存取權是由來源繫結,這表示來源只能存取自行建立的資料。這也適用於安全的環境。

使用者控制項

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

實用連結

特別銘謝

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

主頁橫幅 (透過 Unsplash 上的 Markus Spiske 製作)。