切換語言為:簡體

如何在 Chrome 外掛開發中處理複雜數據結構的儲存

  • 爱糖宝
  • 2024-06-08
  • 2080
  • 0
  • 0

在進行Chrome外掛開發時,經常需要將資料儲存在瀏覽器本地。這看起來是一個簡單直接的任務,但是這個簡單的操作出大事了。

問題描述

最近俺在接觸 Chrome 外掛開發,需要把一個數據存放到瀏覽器的儲存中。這個數據結構有點複雜,它包含一個 Map 和一個數組。我使用 chrome.storage.local API來儲存這個資料,然後在另一個地方獲取資料。儲存資料的程式碼並沒有報錯,但是俺發現獲取的時候獲取結果的內容為空,這是為什麼呢?

下面是我封裝的儲存資料和獲取資料的方法:

// 要儲存的數據結構
const mindDataObj = {
    keywordMap: new Map(),
    mindDataArr: []
};

/**
 * 獲取儲存物件
 * @param {string} key 儲存物件的鍵
 * @returns {Promise<Object>} 返回一個包含儲存物件的 Promise
 */
export async function getObject(key) {
  return new Promise((resolve, reject) => {
    chrome.storage.local.get([key], (result) => {
      if (chrome.runtime.lastError) {
        return reject(chrome.runtime.lastError)
      }
      resolve(result[key] || {})
    })
  })
}

/**
 * 儲存儲存物件
 * @param {string} key 儲存物件的鍵
 * @param {Object} obj 要儲存的物件
 * @returns {Promise<void>} 返回一個 Promise,表示操作完成
 */
export async function saveObject(key, obj) {
  return new Promise((resolve, reject) => {
    chrome.storage.local.set({ [key]: obj }, () => {
      if (chrome.runtime.lastError) {
        return reject(chrome.runtime.lastError)
      }
      resolve()
    })
  })
}


為什麼會這樣?

經過查詢資料發現,chrome.storage.local 的儲存機制只能儲存和檢索序列化的 JSON 物件,雖然JSON可以很好地處理物件和陣列,但對於MapSet等ES6中引入的複雜數據結構,JSON是無法直接序列化和反序列化的。因此,儘管你可能沒有在儲存資料時遇到錯誤,但在嘗試讀取非JSON相容型別的資料時,這些資料將因無法被正確序列化而丟失。

解決方案

總之一句話:chrome.storage.local 只能儲存 JSON 相容的資料型別(如物件、陣列、字串、數字等),Map 和 Set 需要轉換為物件或陣列才能正確儲存。在這裏,我們透過 chrome.storage.local 儲存時需要先進行序列化處理,而在讀取時需要進行反序列化處理。

步驟1: 序列化和反序列化Map物件

我們先增加兩個方法做序列化的處理,serializeMap 和 deserializeMap 方法用於將 Map 物件轉換為陣列,從而可以儲存在 chrome.storage.local 中,並在讀取時將其轉換回 Map 物件。

/**
 * 序列化Map物件
 * @param {Map} map 要序列化的Map物件
 * @returns {Object} 序列化後的物件
 */
function serializeMap(map) {
  return Array.from(map.entries());
}

/**
 * 反序列化Map物件
 * @param {Array} entries 序列化後的物件
 * @returns {Map} 反序列化後的Map物件
 */
function deserializeMap(entries) {
  return new Map(entries);
}


步驟2: 儲存和讀取資料

然後再增加運算元據的方法,saveMindData 和 getMindData 方法用於儲存和獲取 mindDataObj 格式的資料,包括序列化和反序列化步驟。

/**
 * 儲存mindDataObj格式的資料
 * @param {string} key 儲存物件的鍵
 * @param {Object} initMindDataObj 要儲存的物件
 * @returns {Promise<void>} 返回一個 Promise,表示操作完成
 */
export async function saveMindData(key, mindDataObj) {
  const serializedData = {
    keywordMap: serializeMap(mindDataObj.keywordMap),
    mindDataArr: mindDataObj.mindDataArr
  };
  await saveObject(key, serializedData);
}

/**
 * 獲取mindDataObj格式的資料
 * @param {string} key 儲存物件的鍵
 * @returns {Promise<Object>} 返回一個包含mindDataObj格式資料的 Promise
 */
export async function getMindData(key) {
  const serializedData = await getObject(key);
  const mindDataObj = {
    keywordMap: deserializeMap(serializedData.keywordMap || []),
    mindDataArr: serializedData.mindDataArr || []
  };
  return mindDataObj;
}

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.