You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用Async获取chrome.storage数据修复扩展排行榜问题

问题描述

我正在开发一款Google Chrome扩展,在弹窗中展示排行榜。但我是JavaScript新手,不清楚如何正确使用Async。我使用chrome.storage获取存储的分数以展示在排行榜上,再将其从background.js发送至popup.js。问题在于,由于chrome.storage.get是异步操作,我的findScores方法未等待其完成就错误返回了默认空分数。

background.js

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
      console.log(sender.tab ?
                  "from a content script:" + sender.tab.url :
                  "from the extension");
      if (request.type === "request") {
        var scoresVar = findScores(request.table, "All");
        console.log("Sending response " + scoresVar);
        sendResponse({scores: scoresVar})
      } 
      else if (request.type === "score") {
        saveScore(request.website, request.score, request.tab);
        sendResponse("Finished adding score " + request.score);
      }
    }
);

function findScores(table, website) {
    const categories = table.split("-");
    if (categories.includes("personal")) {
        chrome.storage.sync.get([website], function(response) {
            if (!(typeof response[website] === 'undefined')) {
                console.log("Found " + response[website]);
                return response[website];
            }
        });
    } else if (categories.includes("global")){
        // TODO: Add global leaderboards
        return ["-"];
    }
    console.log("Didn't find, on default");
    return ["-"];
}

popup.js

async function requestScores(tableID) {
  var url = "All"
  if (tableID.includes("current")) {
    var url = await getCurrentTab();
  }
  console.log("Sending message to load scores to " + url);
  (async () => {
    const response = await chrome.runtime.sendMessage({type: "request", request: "load scores", table: tableID, tab: url});
    console.log("Received: " + response);
    // add scores to HTML DOM
    });
  })();
}

控制台信息显示我先返回了默认分数并发送至popup.js。我尝试过为函数添加async关键字(以及在scoresVar = await findScores(...)前使用await),但引发了更多问题:findScores仍返回默认值,而background.js发送的是undefined Promise。


修复方案

核心问题

chrome.storage.get是异步API,你的findScores函数在异步操作完成前就执行了return ["-"],直接返回了默认值。同时Chrome的消息监听需要明确告知要异步响应,否则会提前断开连接。

1. 把findScores改成返回Promise

让函数等待异步操作完成后再返回结果:

function findScores(table, website) {
  return new Promise((resolve) => {
    const categories = table.split("-");
    if (categories.includes("personal")) {
      chrome.storage.sync.get([website], function(response) {
        if (response[website] !== undefined) {
          console.log("Found " + response[website]);
          resolve(response[website]);
        } else {
          resolve(["-"]); // 未找到时返回默认值
        }
      });
    } else if (categories.includes("global")){
      // TODO: Add global leaderboards
      resolve(["-"]);
    } else {
      console.log("Didn't find, on default");
      resolve(["-"]);
    }
  });
}

2. 修改消息监听器支持异步响应

使用async/await等待findScores结果,同时返回true告知Chrome要异步发送响应:

chrome.runtime.onMessage.addListener(
  async function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.type === "request") {
      const scoresVar = await findScores(request.table, "All");
      console.log("Sending response " + scoresVar);
      sendResponse({scores: scoresVar});
      return true; // 关键:告诉Chrome不要立即关闭连接
    } 
    else if (request.type === "score") {
      saveScore(request.website, request.score, request.tab);
      sendResponse("Finished adding score " + request.score);
    }
  }
);

3. 简化popup.js的异步逻辑

去掉多余的自执行异步函数,直接在主函数内处理:

async function requestScores(tableID) {
  let url = "All";
  if (tableID.includes("current")) {
    url = await getCurrentTab();
  }
  console.log("Sending message to load scores to " + url);
  try {
    const response = await chrome.runtime.sendMessage({
      type: "request", 
      request: "load scores", 
      table: tableID, 
      tab: url
    });
    console.log("Received: " + JSON.stringify(response));
    // 在这里把scores渲染到HTML DOM中
  } catch (err) {
    console.error("获取分数失败:", err);
  }
}

关键注意点

  • 异步操作必须用Promise或async/await处理,不能像同步函数那样直接return结果
  • Chrome消息监听中,异步发送响应时必须返回true,否则会导致响应无法送达
  • 用try/catch包裹await代码可以捕获消息发送失败的异常

内容的提问来源于stack exchange,提问作者Yasemin Turkoglu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:07:21