Home > Net >  response from await browser.tabs.sendMessage is set in chrome, but not in firefox
response from await browser.tabs.sendMessage is set in chrome, but not in firefox

Time:07-10

I have successfully used await browser.tabs.sendMessage in chrome to get response from the listener, but the same code in firefox does not work. await browser.tabs.sendMessage return immediately and sets response to undefined. In content script inject.js, sendResponse should be called after 1000ms timeout.

I attached a minimalistic example. Any idea why await browser.tabs.sendMessage returns what sendResponse set only in chrome, but not in firefox?

//inject.js
(async () => {
    if (typeof browser === "undefined") {
        var browser = chrome;
    }

    browser.runtime.onMessage.addListener((msg, sender, sendResponse) => {
        console.log(msg);
        setTimeout(function(){
            let pageObject = {a:1};
             sendResponse(pageObject);
        },1000)
        return true;
    });

})();



//background.js
(async () => {
      if (typeof browser === "undefined") {
        var browser = chrome;
      }


//**code for injecting content scripts on extension reload**

  browser.runtime.onInstalled.addListener(async () => {
    let manifest = browser.runtime.getManifest();
    for (const cs of manifest.content_scripts) {
      for (const tab of await browser.tabs.query({ url: cs.matches })) {
        browser.scripting.executeScript({
          target: { tabId: tab.id },
          files: cs.js,
        });
      }
    }
  });

      async function SendMessageToFront(message) {
        let resolve;
        const promise = new Promise(r => resolve = r);
        browser.tabs.query({}, async function (tabs) {
          for (let index = 0; index < tabs.length; index  ) {
            const tab = tabs[index];
    
            if (tab.url) {
              let url = new URL(tab.url)
              if (url.hostname.includes("tragetdomain.com")) {
                var startTime = performance.now()
                let response = await browser.tabs.sendMessage(tab.id, { message: message });
                var endTime = performance.now()
                console.log(`Call to doSomething took ${endTime - startTime} milliseconds`) // this takes 0ms
    
                console.log("got response");
                console.log(response); // this is undefined
                console.log(browser.runtime.lastError); // this is empty
                resolve(response);
                break;
              }
            }
          }
        });
    
        return promise;
      }


      await SendMessageToFront();
})();
  

CodePudding user response:

I guess for the tests in firefox you do the reload of the background script (F5 or the specific button in devtools) Just as you have coded the background you have little hope of getting an answer because every time you reload the background you break the wire with all content scripts injected into the page(s). Move the browser check inside the "SendMessageToFront" function. Move the "SendMessageToFront" function (async is not needed) to the main thread and run that function in the main thread.

/*async*/ function SendMessageToFront(message) {
    if (typeof browser === "undefined")
        var browser = chrome;
    let resolve;
    const promise = new Promise(r => resolve = r);
    browser.tabs.query({}, async function(tabs) {
        for (let index = 0; index < tabs.length; index  ) {
            const tab = tabs[index];
            if (tab.url) {
                let url = new URL(tab.url);
                if (url.hostname.includes("tragetdomain.com")) {
                    var startTime = performance.now()
                    let response = await browser.tabs.sendMessage(tab.id, {'message': message});
                    var endTime = performance.now()
                    console.log(`Call to doSomething took ${endTime - startTime} milliseconds`) // this takes 0ms
                    console.log("got response");
                    console.log(response); // this is undefined
                    console.log(browser.runtime.lastError); // this is empty
                    resolve(response);
                    break
                }
            }
        }
    });
    return promise
}

(async _ => {
    await SendMessageToFront()
})();

in this way you will get an error message as soon as the background is ready which tells you that the content script on the other side does not exists or it's not ready yet, but now, when the content script will be ready, you should just re-launch the function from the background script devtools

(async _ => {
    await SendMessageToFront()
})();

this time you will get the correct answer {a: 1}

  • Related