Chrome Extension短连接消息回复竞争问题【未完待续】

61 阅读3分钟

课题背景与场景

If multiple pages are listening for onMessage events, only the first to call sendResponse() for a particular event will succeed in sending the response. All other responses to that event will be ignored.

---来自《Chrome Extension开发者文档》

官方文档的这句提示词就是在说消息竞争回复的问题,大致意思就是当发送方将短连接消息发送出去后,由于有多个接收方的监听函数在处理这个消息,但最终发送方能接收到的消息回复是多个监听函数中最先调用sendResponse函数返回的那条消息,其他晚到的消息都会被忽略。

其中,需要特别说明的是:根据笔者经验,提示中的“多个监听函数”是可以分布在 多个插件之间或一个插件的多个部分中 的。

但是,由于笔者经验有限,当前只验证成功了以下几种场景:

1. 一个接收方、设置了多个监听函数

此条,适用于一个插件中的Content与Service Worker/option之间,也适用于一个插件向另一个插件发送消息时,接收方插件设置了多个监听函数的场景;

这里,笔者使用“ 一个插件中,Content层作为发送方,Service Worker/option设置了多个监听函数来捕获&处理消息 ”来展示代码。

// service.worker.js

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {

    if (request.type === "GREETING_MESSAGE") {

        console.log("Background script received message:", request.message);
        

        // 延迟响应,以增加content.js首先响应的机会

        setTimeout(() => {

            sendResponse({ response: "Hello from background script!" });

            console.log("Background script sent response.");

        }, 5000); // 延迟5000毫秒
        

        return true; // 表示将异步发送响应

    }

});


chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {

    if (request.type === "GREETING_MESSAGE") {

        console.log("Background script received message:", request.message);

        
        // 延迟响应,以增加content.js首先响应的机会

        setTimeout(() => {

            sendResponse({ response: "Hello from background script-500!" });

            console.log("Background script sent response.");

        }, 500); // 延迟500毫秒
        

        return true; // 表示将异步发送响应

    }

});
// content.js

chrome.runtime.sendMessage({ type: "GREETING_MESSAGE", message: "Hello there!" }, (response) => {
    console.log("Content received response:", response);
});

上面这些代码执行之后,得到的结果是:“Content received response:Hello from background script-500!”;

2. 多个接收方、各自设置了监听函数

此条,适用于一个插件中的Content与Service Worker/option,也适用于一个插件向另一个插件发送消息时,接收方插件设置了多个监听函数的场景;

这里,笔者使用“ 多个插件间,其中一个插件Content层作为发送方,另一个插件的Service Worker与option页面都监听了函数 ”来展示代码。

// 插件2号-接收方:service.worker.js

chrome.runtime.onMessageExternal.addListener((request, sender, sendResponse) => {

    console.log("onMessageExternal script received message:", request);

    if (request.type === "GREETING_MESSAGE") {

        console.log("Background script received message:", request.message);

        // 延迟响应,以增加content.js首先响应的机会

        setTimeout(() => {

            sendResponse({ response: "Hello from background script!" });

            console.log("Background script sent response.");

        }, 500); // 延迟500毫秒
        

        return true; // 表示将异步发送响应

    }

});
// 插件2号-接收方:options.js

chrome.runtime.onMessageExternal.addListener((request, sender, sendResponse) => {

    console.log("option-onMessageExternal script received message:", request);

    // 检查消息类型以确定如何处理

    if (request.type === "GREETING_MESSAGE") {

        console.log("Options page received message:", request.data);

        setTimeout(() => {

            sendResponse({ status: "Message received by options page!" });

            console.log("options script sent response.");

        }, 10); // 延迟10毫秒
        

        return true; // 返回 true 以指示 sendResponse 将异步调用

    }

});
// 插件1号-发送方:service.worker.js

const _extensionId = 'nngbejloggnjlhicebibabhfekciknho'; // 这里请换成自己的插件ID哦~

chrome.runtime.sendMessage(_extensionId, { type: 'GREETING_MESSAGE' }, function (response) {
    console.log('收到来自另一个插件的的回复:', response);
});

上面这些代码执行之后,得到的结果是:“Content received response:Message received by options page”;

写在最后

虽然由于笔者现在的经验甚少、暂时只找到了以上这两种场景,但是往后如果验证完成其他场景的,笔者也会及时更新的哦~