简体   繁体   中英

Chrome extension long-lived message connection - how to use callback functions?

For a while I've been using chrome.runtime.sendMessage(message, callback) for messages from my content script that need to run a callback function after receiving a response from the background.

I've also got a long-lived connection that is used for sending messages from the background to the content script (without it being a response to a message initiated by the content script):

backgroundPort = chrome.runtime.connect({ name: "contentScript" });
backgroundPort.onMessage.addListener(function(message){
  if (message["action"] == "something"){
    // Do stuff
  }
});

As far as I can tell, backgroundPort.postMessage() does not support callback messages which means messages that have a callback need to use chrome.runtime.sendMessage() .

The problem with this approach is that there is a lot of overhead in setting up a new connection between content script/background for each message, so I'm trying to get callback functionality into the existing long-lived connection through backgroundPort , but it gets kind of messy.

Anyone who's been able to come up with an elegant solution?

If you look at your background script as socket server (Port object is basically simulating sockets), you could use something called "acknowledgments" that is used in Nodejs, socket.io library.

Basically you store your callbacks functions inside object by giving them unique identifier that you pass to the other side.

// on the sending side

// this variable will store callbacks
var acknowledgments = {};

var port = chrome.runtime.connect();

// this variable will be unique callback idetifier
var address = Math.random().toString(36);

// You create acknowledgment by identifying callback
acknowledgments[address] = function (data) {
    // callback function
    // do what you like with result data
};

port.postMessage({
    acknowledgment: address,
    data: messageData
})

port.onMessage.addListener(function (message) {
    var callback = acknowledgments[message.acknowledgment];
    if (callback) {
        callback(message.data);
        // don't forget to unset acknowledgment, because it's 
        // supposed to exists only until it's been called.
        delete acknowledgments[message.acknowledgment];
        return;
    }

    // other message types handling
});

Other side passes result with that unique identifier returned, by which you an identify what to do.

// on the listening side
chrome.runtime.onConnect.addListener(function (port) {
    port.onMessage.addListener(function (message) {
        if (message.acknowledgment) {
            // do stuff you need to do
            // then return result
            port.postMessage({
                acknowledgment: message.acknowledgment
                data: stuffYouHaveDoneResult
            });
        }
    });
});

chrome.runtime.sendMessage works using "Port" object at lower level so the actual implementation of sendMessage callback should be similar to this in principle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM