JSON.stringify 使用時機

 您觀察得非常仔細!chrome.runtime.sendMessagepayload(或訊息物件本身)是否需要 JSON.stringify,主要取決於您要傳遞的數據類型以及您希望如何處理它。

核心原則:

chrome.runtime.sendMessage 的訊息參數(message必須是 JSON-ifiable 的。這意味著它可以被安全地序列化為 JSON 字串,然後再被反序列化回原始的 JavaScript 類型。

常見的 JSON-ifiable 類型包括:

  • 基本類型: String, Number, Boolean, null.

  • 物件 (Object): 只包含 JSON-ifiable 值的普通 JavaScript 物件。

  • 陣列 (Array): 只包含 JSON-ifiable 值的陣列。

不能直接作為訊息傳遞的類型(需要特殊處理或避免):

  • Functions

  • DOM Nodes

  • undefined (在序列化過程中可能會被忽略或轉為 null,取決於上下文)

  • Dates (會被轉換為 ISO 8601 字串)

  • RegExp

  • Error objects (直接傳遞會丟失很多資訊,最好提取 messagestack 作為字串)

  • Map, Set (需要先轉換為 Array 或 Object)

  • 包含循環引用的物件

JSON.stringify 的使用時機:

  1. 不使用 JSON.stringify (推薦的常見情況):

    • 當您傳遞的 payload 本身就是一個簡單的 JavaScript 物件或陣列,且其所有屬性/元素都是 JSON-ifiable 的時,您不需要手動調用 JSON.stringify

    • Chrome 的訊息傳遞系統會自動為您處理序列化和反序列化。

    • 示例:

            // popup.js
      const itemData = { title: "開會", time: "2024-08-01T10:00:00Z" };
      chrome.runtime.sendMessage({ type: 'ADD_ITEM', payload: itemData }); // 直接傳遞物件
      
      // background.js
      chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.type === 'ADD_ITEM') {
          console.log(request.payload.title); // 可以直接訪問屬性
        }
      });
          
    • 這是最常見也是最方便的做法。

  2. 使用 JSON.stringify (較少見,特定情況):

    • 情況 A:如果您想傳遞一個已經是 JSON 字串的數據。 例如,您從某個地方獲取到的是一個 JSON 字串,並且您想原樣傳遞它,讓接收端自己去 JSON.parse

    • 情況 B:如果您要傳遞的物件中包含一些非標準的 JSON-ifiable 類型,但您希望通過 JSON.stringify 的第二個參數 (replacer function) 或 toJSON 方法來自定義其序列化行為。 這種情況比較高級和少見。

    • 情況 C:如果您在某些特殊情況下,需要確保傳遞的就是一個純粹的字串,避免任何自動轉換。

    • 情況 D(您之前的例子):傳遞 Error 物件時。

      • 直接傳遞 Error 物件 (chrome.runtime.sendMessage({ type: "AUTH_ERROR", payload: error });) 通常會導致資訊丟失,因為 Error 物件本身不是標準的 JSON-ifiable 結構,其 message, stack, name 等屬性在序列化時可能不會被完整保留。

      • 因此,對於 Error 物件,更好的做法是手動提取其重要屬性並構建成一個普通物件,或者使用 JSON.stringify(error, Object.getOwnPropertyNames(error)) 來嘗試捕獲更多屬性並將其轉換為字串。然後在接收端 JSON.parse

              // popup.js - 發送 Error
        } catch (error) {
            chrome.runtime.sendMessage({
                type: "AUTH_ERROR",
                // 手動構建一個包含錯誤信息的普通物件
                payload: {
                    message: error.message,
                    name: error.name,
                    stack: error.stack // stack 可能是個很長的字串
                }
                // 或者使用您之前的 stringify 方法
                // payload: JSON.stringify(error, Object.getOwnPropertyNames(error))
            });
        }
        
        // background.js - 接收 Error
        chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
            if (request.type === "AUTH_ERROR") {
                // 如果 popup 發送的是普通物件
                console.error("Error from popup:", request.payload.message);
                // 如果 popup 發送的是 stringify 後的字串
                // const errorDetails = JSON.parse(request.payload);
                // console.error("Error from popup:", errorDetails.message);
            }
        });
            

總結:

  • 大多數情況下,您不需要手動對 payload 使用 JSON.stringify 直接傳遞簡單的 JavaScript 物件或陣列,Chrome 會自動處理序列化。

  • 只有在特殊情況下,例如處理 Error 物件、自定義序列化行為、或者您明確需要傳遞一個 JSON 字串時,才需要考慮使用 JSON.stringify

  • 當您使用了 JSON.stringify 發送數據時,接收端通常需要使用 JSON.parse 來將其還原。

對於您正常的 itemData(包含標題、時間等),直接傳遞物件本身是最佳實踐。對於錯誤處理,像您之前那樣對 Error 物件進行 JSON.stringify 是一種確保能傳遞更多錯誤細節的方法。

留言

這個網誌中的熱門文章

Offscreen Canvas

外部網頁新增 Google 日曆行程(URL模板)

計算 Canvas 文字最大字體