Migrating from sendMessage to using port messaging

1,071 views
Skip to first unread message

peter....@gmail.com

unread,
Mar 10, 2021, 8:25:47 AM3/10/21
to Chromium Extensions
Recently I've been noticing lots of errors related to "Receiving end does not exist". My code currently uses lots of "chrome.tabs.sendMessage()" calls to automate filling in some text fields on forms.

Current setup:
background.js (in chrome.tabs.onUpdated.addListener routine): chrome.tabs.sendMessage(tab.id, dataArray, callBack);

content_load.js (in which is a content_script in Manifest): chrome.runtime.onMessage.addListener(() => { });

Now, I don't always need to use a callback method, so having the content script not return anything is an issue that triggers the error mentioned above. Having the content script always return something fixes it. However, even after closing tabs I see the error pop up. My scripts run quite a bit on the same tab, and from my reading, it seems like using the ports api would be better for longevity of message passing.

Am I understanding correctly that the above only sends the message to the 1 tab?

If I start migrating my code to use ports, I don't see anyway for a port to exist on 1 tab and only send to that tab? How does my background script know which tab/port to post a message to?

New setup:
background.js:
var _port = null;
chrome.runtime.onConnect.addListener(function(port) { _port = port); });
chrome.tabs.onUpdated.addListener(() => { _port.postMessage({'hello from port'}); });

content_load.js:
var port = chrome.runtime.connect({name: 'test'});
port.onMessage.addListener(function(msg) { console.log(msg); });

The new setup does indeed work, however I don't know if it's actually better. I don't ever need message passing to be cross-tab, so I don't know if the port things are tab specific? If I use the script on a couple of different tabs at the same time, do things route correctly? My current setup does because of the tab specific message sending...
Message has been deleted

wOxxOm

unread,
Mar 10, 2021, 9:23:05 AM3/10/21
to Chromium Extensions, peter....@gmail.com
Reposting to fix typos, sorry.

You can simply suppress the error by accessing chrome.runtime.lastError, no need for port messaging.

chrome.runtime.sendMessage({}, () => chrome.runtime.lastError);

You can also define a smarter function:

function ignoreReceiverError() {
  const err = chrome.runtime.lastError;
  const msg = err && err.message; // or just err?.message in new Chrome
  if (!/Receiving end does not exist|The message port closed/.test(msg)) {
    console.error(msg);
  }
}

chrome.runtime.sendMessage({}, ignoreReceiverError); 

And of course you can define a wrapper function that sends messages and suppresses the error.

As for port messaging, it's the low-level API that powers sendMessage under the hood. Using it directly is really needed only when sending a lot of messages to the same target or detecting the moment the target is closed/removed (the latter is particularly helpful for the extension popup or web iframes).

If you still want to switch, you'll have to re-implement what sendMessage does under the hood by keeping track of tabs and their ports.
Here's a bare-bones example: https://stackoverflow.com/a/61600254
AFAIK There's at least one js library which you can find yourself.

peter....@gmail.com

unread,
Mar 10, 2021, 9:45:30 AM3/10/21
to Chromium Extensions, wOxxOm, peter....@gmail.com
w0xx0m, thanks for the explanation! I've noticed that a couple of my sendMessages that error out will work if I send them again right away. Basically I send the message, check the error in the return/callback, and if it's that 'Receiving end does not exist', I resend the message. This doesn't work all the time because some messages will send correctly but still re-run the sendMessage call.

I really appreciate the stackoverflow link you have. I'd rather not redo the work, but to me it's much cleaner and easier to maintain and extend upon. Thank you so much!
Reply all
Reply to author
Forward
0 new messages