浏览器网页可以很方便的使用 postmessage
与 Chrome 扩展通讯,但是 postmessage
只能传递消息,不能传递 promise,如果遇到网页需要等待 Chrome 扩展返回的 promise,处理起来就比较麻烦了。
现在可以通过封装 postmessage
发送消息 和 监听 message
接收消息,然后直接返回 promise
,这下就方便多了。
网页发送并接收 promise
消息
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>test chrome extension</title>
</head>
<body>
<div id="btns">
<button class="install">测试发送并接收消息</button>
</div>
<script>
async function waitForPostMessage({
timeout = 5000,
type,
data = {},
lang,
}) {
const returnType = `RETURN_${type}`;
let timeoutId = null;
window.postMessage({
type: type,
data: { ...data, timeout, lang },
});
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
reject(new Error("timeout"));
}, timeout);
});
const responsePromise = new Promise((resolve, reject) => {
function handleMessage(event) {
timeoutId = setTimeout(() => {
console.log("removeEventListener");
window.removeEventListener("message", handleMessage);
}, timeout);
const messageData = event?.data;
console.log("🚀 ~ handleMessage ~ messageData:", messageData);
if (messageData?.type !== returnType) {
return;
}
if (messageData && messageData.type === returnType) {
resolve(messageData);
} else {
reject(new Error("No data received in message"));
}
clearTimeout(timeoutId);
window.removeEventListener("message", handleMessage);
}
window.addEventListener("message", handleMessage);
});
return await Promise.race([responsePromise, timeoutPromise]);
}
document
.querySelector("#btns")
.addEventListener("click", async (event) => {
// 检测安装及Google 可用性
if (event.target.matches(".install")) {
waitForPostMessage({
type: "GLARITY_PING_URL",
timeout: 2000,
})
.then((data) => {
console.log("Received message data:", data?.data);
})
.catch((error) => {
console.error("Failed to receive message:", error);
});
}
});
</script>
</body>
</html>
Chrome 扩展接收并发送消息
content-script.js
// content-script.js
window.addEventListener("message", async (message) => {
const messageData = message.data || {};
const { type, data = {} } = messageData;
switch (type) {
case "GLARITY_PING_URL": {
const res = await Browser.runtime.sendMessage({
type: "PING_URL",
data: data,
});
window.postMessage({ type: "RETURN_GLARITY_PING_URL", data: res });
break;
}
default:
break;
}
});
background.js
// background.js
chrome.runtime.onMessage.addListener((request, sender) => {
if (request.type === "PING_URL") {
const { url = "https://google.com/", timeout } = request.data || {};
return fetch(url)
.then((res) => {
return { ok: res?.ok };
})
.catch(() => {
return { ok: false };
});
}
});