return Promise 的正確使用方法

 








你又遇到了一個非常經典的非同步 (asynchronous) 問題!這和之前 chrome.alarms.get() 的情況是完全一樣的。

簡單的答案是:你的變數 isearly 的值不是一個 int (整數),而是一個 Promise 物件。


錯誤的根本原因

讓我們一步步分解你的程式碼,看看它實際上做了什麼:

  1. chrome.storage.local.get(['isearly'])

    • 這行程式碼被執行。它是一個非同步操作,意思是它會去背景讀取資料,但不會停下來等待結果。

    • 立即回傳一個 Promise 物件。這個 Promise 物件可以看作是一個「取貨單」,它承諾「我稍後會把資料給你」。

  2. .then(...).catch(...)

    • 你把取貨單(Promise)交給了 .then().catch()。這相當於告訴程式:「等貨到了(操作成功),就執行 .then() 裡面的程式碼;如果送貨出錯(操作失敗),就執行 .catch() 裡面的程式碼。」

  3. const isearly = ...

    • 你的變數 isearly 被賦予的值,是整個 Promiseget(...).then(...).catch(...))的最終回傳值。

    • 一個 Promise 鏈本身回傳的仍然是一個 Promise

結論:你的程式碼執行完畢後,isearly 變數裡面裝的是一個 Promise 物件,而不是你期望的數字 0parseInt(result.isearly)

比喻:
你去餐廳點餐(chrome.storage.local.get),服務生給了你一個取餐的號碼牌 (Promise)。你不能直接把這個號碼牌吃掉。你必須等待叫到你的號碼時(.then() 被執行),才能拿到真正的餐點(result)。

你的程式碼相當於把號碼牌存到了 isearly 變數裡。


如何修正

解決方案和之前一樣:你需要把「使用 isearly 這個值」的程式碼,放到一個能夠等待 Promise 完成的地方。

方法一:使用 async/await (最推薦,最清晰)

這是處理非同步操作最現代、最易讀的方式。你需要將你的邏輯包在一個 async 函式中。

JavaScript
// 創建一個 async 函式
async function getEarlySetting() {
    try {
        // 1. 使用 await 來「暫停」函式,直到 storage.get 完成,並直接取得 result
        const result = await chrome.storage.local.get(['isearly']);

        // 2. 檢查 result 是否存在,以及 result.isearly 是否有值
        //    這比 if(result) 更安全,因為空物件 {} 也是 true
        if (result && result.isearly) {
            // 3. 回傳解析後的整數
            return parseInt(result.isearly);
        } else {
            // 4. 回傳預設值
            return 0;
        }
    } catch (error) {
        showMessage({ name: '發生錯誤!錯誤訊息請看控制台。', delay: 10, type: 'error' });
        console.error("Error retrieving data:", error);
        // 發生錯誤時也回傳預設值
        return 0;
    }
}

// --- 如何使用這個 async 函式 ---
async function mainLogic() {
    // 呼叫 getEarlySetting 並用 await 取得它回傳的整數值
    const isearly = await getEarlySetting(); 

    // 現在,isearly 變數就是你真正想要的數字了!
    console.log(`提前通知的時間是: ${isearly} 分鐘`); 
    console.log(typeof isearly); // 輸出: "number"

    // --- 在這裡執行所有需要用到 isearly 值的後續操作 ---
    // 例如: someFunctionThatUses(isearly);
}

// 執行你的主要邏輯
mainLogic();
  

方法二:繼續使用 .then() (將後續操作放進去)

如果你不想使用 async/await,那麼你必須接受一個事實:所有需要用到 isearly 值的程式碼,都必須被放在 .then() 的回呼函式裡面

JavaScript
function initialize() {
    chrome.storage.local.get(['isearly']).then((result) => {
        let isearly = 0; // 先設定一個預設值

        if (result && result.isearly) {
            isearly = parseInt(result.isearly);
        }

        // --- 在這裡執行所有需要用到 isearly 值的後續操作 ---
        console.log(`提前通知的時間是: ${isearly} 分鐘`);
        console.log(typeof isearly); // 輸出: "number"
        
        // 範例:呼叫一個函式並把 isearly 當作參數傳進去
        setupNotifications(isearly);

    }).catch((error) => {
        showMessage({ name: '發生錯誤!錯誤訊息請看控制台。', delay: 10, type: 'error' });
        console.error("Error retrieving data:", error);
        
        // 即使出錯,也要用預設值執行後續操作
        const isearly = 0;
        setupNotifications(isearly);
    });

    // ⚠️ 在這裡 (then 的外面) 存取 isearly 是不可能的,因為程式碼會先執行到這裡!
}

function setupNotifications(earlyMinutes) {
    // ... 你的設定邏輯 ...
    console.log(`正在根據 ${earlyMinutes} 分鐘的設定來初始化通知。`);
}

// 執行初始化
initialize();
  

總結

  • 你的錯誤:試圖將一個 Promise (一個承諾/號碼牌) 當作一個 number (一個實際的值) 來使用。

  • 解決方案:必須使用 await將程式碼移入 .then() 等待承諾兌現,拿到實際的值之後,再進行後續操作。

留言

這個網誌中的熱門文章

Offscreen Canvas

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

計算 Canvas 文字最大字體