Search code examples
javascriptgoogle-chrome-extensionfirefox-addon-webextensions

In chrome/firefox extension API, how do I get a chained response from port without sending a new message?


For one time messages, the sender send a message, the receiver receives a response via a callback.

// Sender
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
  console.log(response.farewell);
});

// Receiver
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
      if (request.greeting == "hello")
          sendResponse({farewell: "goodbye"});
  }
);

For port communications, the API doc and examples are like this where the sender sends a message, the receiver sends a NEW message but not as a reponse.

For example

// Sender
port?.postMessage({greeting: "hello"});

port.onMessage.addListener(function(msg) {
  if (msg.farewell)
      console.log("Farewell is", msg.farewell)
});
// Receiver
port.onMessage.addListener(function(msg) {
  if (msg.greeting == "hello")
    port.postMessage({farewell: "goodbye"});
});

Is there anyway to mimic the one-time message communication using the port communication that can return response either as callback or a promise so that I can chained the logic. Chaining the response, especially with async await with browser-polyfil, makes the code logic flow more natural.


Solution

  • There is no callback response for port communication. However, you can mimic with a async wrapper that waits for a specific message. This will not just catch the recevier's reponse but all msg.subject that matches. However, with this, you can still do all your logic in one function rather than piecemeal in the listener.

    async function waitForResponse(port, subject) {
      return new Promise((resolve) => {
        const callback = (msg) => {
          if (msg.subject === subject) {
            port.onMessage.removeListener(callback);
            resolve(msg);
          }
        };
        port.onMessage.addListener(callback);
      });
    }