如何正确使用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
相关产品推荐
相关产品推荐

