Chrome 扩展计时器并行实例和端口连接问题
Chrome extension timer parallel instances and port connection issues
我正在尝试 运行 在 chrome 扩展程序的后台运行计时器脚本。在用户从 popup.js
.
启动定时器后,我希望定时器成为 运行ning
我做了什么: 我在 popup.js
和 background.js
之间建立了一个端口连接并且成功了。它成功 logs
我的 popup.js
控制台时间。
(问题总结如下)
Popup.js:
//create a port
let port = chrome.runtime.connect({name:"timeScript"});
//in this certain event send duration to background and receive the constantly updating time
play.addEventListener("click", () => {
port.postMessage({duration: 6*60});
port.onMessage.addListener((x) => {
console.log(`${x.time[0]} : ${x.time[1]}`);
});
});
Background.js:
chrome.runtime.onConnect.addListener((port) => {
console.assert(port.name = "timeScript");
//listen for messages from popup.js
port.onMessage.addListener((x) => {
let duration = x.duration;
//timer logic
function startTimer(duration) {
var start = Date.now(), diff, minutes, seconds;
function timer() {
diff = duration - (((Date.now() - start) / 1000) | 0);
minutes = (diff / 60) | 0;
seconds = (diff % 60) | 0;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
if (diff <= 0) {
start = Date.now() + 1000;
}
//Send message to the popup.js
port.postMessage({time: [`${minutes}`, `${seconds}`]});
};
timer();
setInterval(timer, 1000);
}
//timer logic end
startTimer(duration)
})
})
问题:
当我 play
我的 popup.js
的计时器在我已经 played
它一次之后,第二个计时器开始 运行ning 并行到第一个。如果我第三次按下它,第三个计时器将 运行 并行,依此类推。
我知道当弹出 window 关闭时,popup.js
停止 运行ning 因此,端口连接关闭并抛出错误:Uncaught Error: Attempting to use a disconnected port object
在 background.js
中。我希望计时器保持 运行ning 并在再次启动时重新连接到 popup.js
。我对此进行了研究,但到目前为止一无所获。
我认为这些问题是由于 'async chrome API functions'(因为我在某处读到类似的东西)造成的,但我无法指出问题所在。
这是我的manifest.json,以备不时之需。
清单:
{
"name": "Timer",
"description": "Timer",
"version": "0.0.0.1",
"manifest_version": 2,
"icons": {
"128": "img/icon_128.png",
"48": "img/icon_48.png",
"16": "img/icon_16.png"
},
"browser_action": {
"default_icon": "img/icon_16.png",
"default_popup": "popup.html"
},
"background": {
"page": "background.html",
"persistent": true
}
}
与“异步”无关。问题是您的计时器正在使用对 port
的引用,但弹出窗口仅在显示时运行,因此它在关闭时终止连接,使 port
无法使用(这是您看到的错误)。当弹出窗口再次打开时,您的 onConnect 侦听器将创建一个新的 port
除了旧计时器使用的旧的。
解决办法是将定时器提取到全局范围内,使port
全局化:
let popupPort;
chrome.runtime.onConnect.addListener((port) => {
popupPort = port;
port.onMessage.addListener((x) => {
startTimer(x.duration);
});
port.onDisconnect.addListener(() => {
popupPort = null;
});
});
function startTimer(duration) {
// ...............
function timer() {
// ...............
if (popupPort) {
popupPort.postMessage({time: [`${minutes}`, `${seconds}`]});
}
}
// ...............
}
这是一个简化的示例,如果在两个不同的 windows 中同时打开两个弹出窗口,它将无法正常工作。要使其适用于任意数量的弹出窗口,您需要将 popupPort 转换为数组或 Set
,正确更新它,并在每个条目上调用 postMessage。
我正在尝试 运行 在 chrome 扩展程序的后台运行计时器脚本。在用户从 popup.js
.
我做了什么: 我在 popup.js
和 background.js
之间建立了一个端口连接并且成功了。它成功 logs
我的 popup.js
控制台时间。
(问题总结如下)
Popup.js:
//create a port
let port = chrome.runtime.connect({name:"timeScript"});
//in this certain event send duration to background and receive the constantly updating time
play.addEventListener("click", () => {
port.postMessage({duration: 6*60});
port.onMessage.addListener((x) => {
console.log(`${x.time[0]} : ${x.time[1]}`);
});
});
Background.js:
chrome.runtime.onConnect.addListener((port) => {
console.assert(port.name = "timeScript");
//listen for messages from popup.js
port.onMessage.addListener((x) => {
let duration = x.duration;
//timer logic
function startTimer(duration) {
var start = Date.now(), diff, minutes, seconds;
function timer() {
diff = duration - (((Date.now() - start) / 1000) | 0);
minutes = (diff / 60) | 0;
seconds = (diff % 60) | 0;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
if (diff <= 0) {
start = Date.now() + 1000;
}
//Send message to the popup.js
port.postMessage({time: [`${minutes}`, `${seconds}`]});
};
timer();
setInterval(timer, 1000);
}
//timer logic end
startTimer(duration)
})
})
问题:
当我
play
我的popup.js
的计时器在我已经played
它一次之后,第二个计时器开始 运行ning 并行到第一个。如果我第三次按下它,第三个计时器将 运行 并行,依此类推。我知道当弹出 window 关闭时,
popup.js
停止 运行ning 因此,端口连接关闭并抛出错误:Uncaught Error: Attempting to use a disconnected port object
在background.js
中。我希望计时器保持 运行ning 并在再次启动时重新连接到popup.js
。我对此进行了研究,但到目前为止一无所获。
我认为这些问题是由于 'async chrome API functions'(因为我在某处读到类似的东西)造成的,但我无法指出问题所在。
这是我的manifest.json,以备不时之需。
清单:
{
"name": "Timer",
"description": "Timer",
"version": "0.0.0.1",
"manifest_version": 2,
"icons": {
"128": "img/icon_128.png",
"48": "img/icon_48.png",
"16": "img/icon_16.png"
},
"browser_action": {
"default_icon": "img/icon_16.png",
"default_popup": "popup.html"
},
"background": {
"page": "background.html",
"persistent": true
}
}
与“异步”无关。问题是您的计时器正在使用对 port
的引用,但弹出窗口仅在显示时运行,因此它在关闭时终止连接,使 port
无法使用(这是您看到的错误)。当弹出窗口再次打开时,您的 onConnect 侦听器将创建一个新的 port
除了旧计时器使用的旧的。
解决办法是将定时器提取到全局范围内,使port
全局化:
let popupPort;
chrome.runtime.onConnect.addListener((port) => {
popupPort = port;
port.onMessage.addListener((x) => {
startTimer(x.duration);
});
port.onDisconnect.addListener(() => {
popupPort = null;
});
});
function startTimer(duration) {
// ...............
function timer() {
// ...............
if (popupPort) {
popupPort.postMessage({time: [`${minutes}`, `${seconds}`]});
}
}
// ...............
}
这是一个简化的示例,如果在两个不同的 windows 中同时打开两个弹出窗口,它将无法正常工作。要使其适用于任意数量的弹出窗口,您需要将 popupPort 转换为数组或 Set
,正确更新它,并在每个条目上调用 postMessage。