使用索引資料庫的最佳做法

瞭解在 IndexedDB 為熱門狀態管理程式庫之間同步處理應用程式狀態的最佳做法。

使用者初次載入網站或應用程式時,通常需要大量的 建構用來轉譯 UI 的初始應用程式狀態。舉例來說,有時候 應用程式必須先驗證使用者用戶端,然後提出幾個 API 要求 網頁上需要顯示的資料

將應用程式狀態儲存在 IndexedDB 可以有效加快 重複造訪的載入時間接著,應用程式可在背景與任何 API 服務同步 延後更新 UI 並更新 UI,方法是使用 stro-while- 重新驗證策略。

IndexedDB 的另一個優點是儲存使用者產生的內容,做為暫存儲存庫 。

不過,使用 IndexedDB 時 對初次使用 API 的開發人員來說 可以直接區分。本文將解答常見問題和 探討在索引資料庫中保留資料時需要留意的一些重要事項。

讓您的應用程式容易預測

但是 IndexedDB 的複雜之處在於 (開發人員) 無法控制。本節將探討許多您必須留意的問題。 最終介紹了 IndexedDB

並非所有平台上的內容都能儲存在 IndexedDB 中

如要儲存使用者產生的大型檔案 (例如圖片或影片),不妨試著儲存 做為 FileBlob 物件這適用於部分平台,但在其他平台上無法運作。Safari 開啟 iOS 尤其無法在 IndexedDB 中儲存 Blob

幸好,將 Blob 轉換為 ArrayBuffer 並不困難,反之亦然。儲存 IndexedDB 中的 ArrayBuffer 獲得充分支援。

但請注意,Blob 具有 MIME 類型,而 ArrayBuffer 則沒有。您需要 儲存類型與緩衝區,以便正確進行轉換。

如要將 ArrayBuffer 轉換為 Blob,只需使用 Blob 建構函式即可。

function arrayBufferToBlob(buffer, type) {
  return new Blob([buffer], { type: type });
}

另一種方向比較複雜,並且為非同步程序。您可以使用 FileReader 物件,將 blob 讀取為 ArrayBuffer。讀完後loadend 事件就會觸發您可以將這個程序納入 Promise 中,如下所示:

function blobToArrayBuffer(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.addEventListener('loadend', () => {
      resolve(reader.result);
    });
    reader.addEventListener('error', reject);
    reader.readAsArrayBuffer(blob);
  });
}

寫入儲存空間可能失敗

寫入索引資料庫時發生錯誤的原因有很多,在某些情況下 但不可否認,其實這類情況 並非由開發人員控管舉例來說,某些瀏覽器目前 在私密瀏覽模式下寫入 IndexedDB。 使用者的裝置磁碟空間即將即將用盡, 瀏覽器會限制您儲存任何內容

因此,請您務必一律在網站的 。這也表示,建議您將應用程式狀態保留在記憶體中 ( 而且在私密瀏覽模式下執行時,使用者介面不會中斷。 將無法使用儲存空間 (即使其他應用程式功能需要儲存空間 工作)。

您可為 error 事件新增事件處理常式,藉此擷取 IndexedDB 作業中的錯誤 每次建立 IDBDatabaseIDBTransactionIDBRequest 物件時,系統都會擷取此物件。

const request = db.open('example-db', 1);
request.addEventListener('error', (event) => {
  console.log('Request error:', request.error);
};

儲存的資料可能已遭使用者修改或刪除

有別於伺服器端資料庫,可以限制未經授權的存取,而用戶端資料庫則有所不同, 只要使用瀏覽器擴充功能和開發人員工具,就可以由使用者清除。

使用者可能會不常修改儲存在本機的資料,但使用者很常遇到這種情況 清除指令。請務必讓您的應用程式能夠處理這兩種情況,而不會發生錯誤。

儲存的資料可能已過時

與上一節類似,即便使用者未自行修改資料, 儲存空間中的資料可能是由舊版程式碼寫入 包含錯誤的版本

IndexedDB 內建結構定義版本支援,並透過其升級 IDBOpenDBRequest.onupgradeneeded()敬上 方法;不過,您仍需撰寫升級程式碼,讓其能夠處理使用者 來自前一版本 (包括發生錯誤的版本)。

單元測試在此處相當實用,因為要手動測試所有可能性通常無法測試 升級路徑和案件

維持應用程式效能

IndexedDB 的其中一項重要功能是非同步 API,但別忘了 因此使用這項工具時就不必擔心成效如何。有一些範例 不當使用仍有可能封鎖主執行緒,導致卡頓和沒有回應的情況。

一般而言,將資料寫入 IndexedDB 的讀取和寫入不應大於資料所需的大小 降低頻率

雖然 IndexedDB 可以將大型的巢狀物件儲存為單一記錄 (而且這種做法 從開發人員的角度來看,這個做法其實很方便,則應該避免這樣。 這是因為在 IndexedDB 儲存物件時,必須先建立一個 結構化副本 而結構化複製程序會在主執行緒上發生。值越大 物件,封鎖時間越長。

這在規劃如何將應用程式狀態保存至已建立索引的資料庫時,會遇到一些挑戰 最熱門的狀態管理程式庫 (例如 Redux) 使用, 將整個狀態樹狀結構視為單一 JavaScript 物件

雖然以這種方式管理狀態有許多好處 (例如讓程式碼更容易理解 偵錯),而且只將整個狀態樹狀結構儲存為單一記錄在 IndexedDB 中 反覆做出調整 (即使受到節流/拆解) 的影響,您就能輕鬆踏出第一步 不需要封鎖主執行緒,就會提高寫入錯誤的可能性, 在某些情況下,這甚至會導致瀏覽器分頁當機或沒有回應。

不應將整個狀態樹狀結構儲存在單一記錄中,而應拆分為個別記錄 並只更新實際變更的記錄。

同樣的,如果您在 IndexedDB 中儲存圖片、音樂或影片等大型項目,也是一樣。儲存各項商品 有專屬索引鍵,而不是大型物件內部,因此你可以擷取結構化資料 不必一併支付擷取二進位檔案的費用。

如同大多數最佳做法,這並不是萬無一失的規則。否則就無法 分割狀態物件,並只寫入最低程度的變更集,再將資料拆解成子樹狀結構 且只編寫這些物件仍最好一律編寫整個狀態樹狀結構。小 改善內容反而比沒有改善空間來得好。

最後,請務必評估成效影響 所編寫的程式碼雖然對索引資料庫進行小規模寫入確實的成效會優於大型寫入 寫入作業,只有在應用程式寫入 IndexedDB 後, 長時間的任務 封鎖主執行緒並損及使用者體驗。請務必進行評估 瞭解這些最佳化項目

結論

開發人員可以利用 IndexedDB 這類用戶端儲存機制,改善 使應用程式得以保持運作狀態,同時減少時間 需要先載入初始狀態。

正確使用 IndexedDB 能大幅改善使用者體驗, 如果沒有處理錯誤情況,則可能導致應用程式異常終止,並讓使用者感到不滿。

用戶端儲存空間涉及許多非您控制的因素,因此您的程式碼必須很好 並能妥善處理錯誤 即使是一開始可能不太可能發生的錯誤