I´m working on a chrome-extension which uses the indexedDB-Wrapper Dexie, several jQuery-Libraries and syncfusions eGrid to display and modify the database. I know this question was asked several times before, but now I discovered some weird behaviour.
My Setup:
When I´m reloading my extension everything is fine. I´m injecting a scrollable list of names with my content-script. This also works when I´m reloading the tab. But when I opened the index.html before (popup.html in the official documentation) the sendResponse from background-script stops working after some time. Reloading the tab would not help then. I was searching for hours, found a lot of similiar cases and some entrys on googles bugtracker where they claimed this problem was already fixed. I also know that I have to use return true if I have async funtions like with indexedDB.
So to give you some more information, I will list my shortened scripts.
Content-Script
chrome.runtime.sendMessage({greeting: 'getNames'},function(response){
$('.names-container').append(response.farewell);
});
chrome.runtime.sendMessage({greeting: 'getData'+name},function(name){
chrome.runtime.sendMessage({greeting: 'delete'},function(response){
console.log(response.farewell);
});
chrome.runtime.sendMessage({greeting: 'set'}, function(response) {
console.log(response.farewell);
});
});
Background-Script
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
if(message.greeting == 'getNames'){
// Get array of names from idb and send it back
idb.opendb().then(function(a){
sendResponse(a);
});
return true;
} else if(message.greeting.indexOf('getData') >= 0){
// get more information for selected name
idb.opendb().then(function(a){
sendResponse(a);
});
return true;
} else if(message.greeting == 'delete'){
// further processing to delete some stuff
idb.opendb().then(function(a){
sendResponse(a);
});
return true;
} else if(message.greeting == 'set'){
// synchronous function
// do something ...
return false;
} else {
// Do something
}
//return true;
});
funtion indexhtml(){
chrome.runtime.sendMessage(
"notifications",
function (response) {
console.log(response);
}
);
}
Index.html
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
if(request == 'notifications'){
notifications();
}
sendResponse("Message received from background-page for "+request);
});
Manifest
{
"manifest_version": 2,
"name": "MyExtension",
"description": "Some desc...",
"version": "0.2",
"background": {
"scripts": ["js/jquery-2.1.4.min.js", "js/background.js", "...",
"persistent": true
},
"default_locale": "en",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["js/jquery-2.1.4.min.js"]
},
{
"matches": ["https://domain.tld/*"],
"js": ["js/jquery-2.1.4.min.js", "js/contentscript.js"],
"css" : ["css/contentscript.css",
"run_at": "document_start"
}
],
"icons": {
"16": "images/icon-16x16.png",
"48": "images/icon-48x48.png",
"128": "images/icon-128x128.png"
},
"browser_action": {
"default_icon": "images/icon-128x128.png"
},
"permissions": [
"cookies", "tabs", "alarms", "webRequest", "webRequestBlocking",
"contextMenus", "<all_urls>", "storage"
],
"content_security_policy": "script-src 'self' 'unsafe-eval';
object-src 'self'"
}
It is difficult for me to debug this behaviour, since I can´t exactly know when the Error Attempting to use a disconnected port object
appears. It looks like the port doesn´t gets closed correctly after the sendResponse is executed and only if the index.html was opened.
Finally the shortened Error-Message:
Error: Attempting to use a disconnected port object
at Error (native)
at PortImpl.postMessage (extensions::messaging:65:22)
at Port.publicClass.(anonymous function) [as postMessage] (extensions::utils:94:26)
at responseCallback (extensions::messaging:163:16)
The idb-Functions are customized and won´t work like I wrote them here, but I just want to show what I´m doing there. I´m using .then()
to sendReponse
when the result is available and return true;
to wait for the result if async. I also searched every script for onMessage
and sendMessage
. The listed functions related to onMessage/sendMessage are all that I´m using, they are not used elsewhere. I´m using a timer for indexhtml()
to save an array containing the notifications in a specified interval and then executing a function at index.html to reload the notifications.
The index.html Tab gets opened via browserAction:
chrome.browserAction.onClicked.addListener(function(tab){
chrome.tabs.create({url: chrome.extension.getURL('index.html')});
});
Okay, I found the answer by myself after adding more and more debugging. The problem here is, that I am using multiple(2) onMessage-Listeners. There is no specific listener to only listen for messages send to my content-page (index.html). Everytime I opened the index.html the additional onMessage-Listener would then be called first if sendMessage were used within my content-script. I wasn´t aware that this onMessage-Listener, embedded into index.html, is called everytime too. I then changed the destination for sendMessage in my content-script - with the same result. There is also a note on googles documentation about this topic:
Note: 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.
Link here
The second problem was, that I used the sendResponse outside of the if clause and this way it got called everytime. So in the end I only had to put the sendResponse inside the if-clause so it only gets called if a specified message from background-page got called via sendMessage.
Background-Script
chrome.windows.getAll({populate:true},function(windows){
windows.forEach(function(window){
window.tabs.forEach(function(tab){
if(tab.url.indexOf(chrome.extension.getURL('index.html')) >= 0){
chrome.tabs.sendMessage(tab.id,{ greeting: "notifications"}, function(response){
console.log(response);
});
}
});
});
});
Index.html
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
if(message.greeting == "notifications-trades"){
Notifications();
sendResponse("Message received from bg "+message.greeting);
//if async add return true;
} else {
//Do something
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With