我正在编写Firefox浏览器扩展程序,并且在如何从后台脚本发送消息之前一直等待内容脚本加载。 这是我要实现的顺序:
很显然,需要加载内容脚本才能使步骤4起作用;否则,该消息将不会被接收。
我看过以前的类似问题,但是大多数答案都是错误的(它们将事件侦听器方法包装在Promise中,这会导致侦听器过多或Promises过多),或者它们似乎不适用于我的情况(这些答案通过将一个回调放在另一个回调中来完全解决了这个问题;在这里不起作用)。
到目前为止,我尝试过的工作是让内容脚本准备就绪后发送一条消息,并且可以正常工作,但是我仍然不确定如何让点击处理程序(来自第1步)等待来自内容脚本(假设的步骤3.5)。 据我所知,除非我有办法在点击处理程序中接收消息,否则我必须在点击处理程序之外定义消息处理程序。
这是我当前的代码,作为最小的工作示例:
background.js
:
let ports = {
'1': null,
'2': null
};
xyz = () => { /*...*/ }
tabHasLoaded = () => { /*...*/ }
browser.runtime.onConnect.addListener(connectHandler);
connectHandler = (p) => {
ports[p.name] = p;
switch (p.name) {
case '1':
ports['1'].addListener(xyz);
break;
case '2':
ports['2'].addListener(tabHasLoaded);
break;
}
};
browser.contextMenus.onClicked.addListener((info, tab) => {
let data, uri;
//...
browser.tabs.create({
url: uri
}).then((tab) => {
// need to wait for tabHasLoaded() to get called
ports['2'].postMessage({
msg: data
})
});
});
1.js
(其他内容脚本):
let myPort = browser.runtime.connect({
name: '1'
});
document.addEventListener("click", (e) => {
myPort.postMessage({
msg: e.target.id
});
});
2.js
(单击上下文菜单后,新选项卡的内容脚本):
let myPort = browser.runtime.connect({
name: '2'
});
myPort.postMessage({
msg: "READY" // tabHasLoaded() should now get called in background.js
});
myPort.onMessage.addListener((msg) => {
// waiting for background.js to send me data
});
是否有理想的方式来处理此问题?
答案 0 :(得分:1)
我仍然认为承诺是可行的方式...
更改代码以使用您的MWE ...请注意,这是未经测试/未经优化的代码,只是为了概述想法...它看起来应该像这样:
background.js
let ports = {
'1': null,
'2': null
};
xyz = () => { /*...*/ }
browser.runtime.onConnect.addListener(connectHandler);
connectHandler = (p) => {
ports[p.name] = p;
switch (p.name) {
case '1':
ports['1'].addListener(xyz);
break;
}
};
browser.contextMenus.onClicked.addListener(async (info, tab) => {
let data, uri;
//...
const tab = await LoadAndWaitForPort2(uri)
ports['2'].postMessage({msg: data})
});
function LoadAndWaitForPort2(uri){
return new Promise((resolve, reject)=>{
const tab
const tabHasLoaded = (evt) => {
if(evt.data.msg === "READY"){
ports['2'].removeListener(tabHasLoaded)
resolve(tab)
} else {
reject("error!")
}
}
ports['2'].addListener(tabHasLoaded)
tab = await browser.tabs.create({url: uri})
})
}
2.js
let myPort = browser.runtime.connect({
name: '2'
});
myPort.postMessage({
msg: "READY" // tabHasLoaded() should now get called in background.js
});
myPort.onMessage.addListener((msg) => {
// waiting for background.js to send me data
});