1

I'm creating a browser extension where I need to capture a full-page screenshot. The process involves sending message signals between popup and background script and content-script. However, the await in the popup isn't waiting for the background script to complete its operation. After calling the message signal it immediately jumps to below code execution.

// Popup (App.tsx)
if (capturetype === 'fullpage'): {
  console.log('Capturing full page...');
  const url = await browser.runtime.sendMessage({
    type: "CAPTURE_FULL_PAGE",
    tab,
  })
  console.log("above function executed, result ->", url) // Executes immediately, url is undefined
}
// Background script
browser.runtime.onMessage.addListener(async (message: any, _sender: any) => {
  if (message.type === "CAPTURE_FULL_PAGE") {
    // Long running operation
    const dimensions = await browser.tabs.sendMessage(tab.id, {
       type: "GET_FULL_PAGE_DIMENSIONS"
    }); // sends message to content-script
    // More async operations, didnt add for now.
    return { success: true, dataUrl: finalImage };
  }
});
// Content Script
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
   if (message.type === "GET_FULL_PAGE_DIMENSIONS") {
        sendResponse({
          width: Math.max(document.documentElement.scrollWidth, document.body.scrollWidth),
          height: Math.max(document.documentElement.scrollHeight, document.body.scrollHeight),
          viewportHeight: window.innerHeight,
          originalScroll: window.scrollY
        });
   }
});

CONSOLE LOG:

full page...
above function executed, result -> undefined
// Later, background operations complete but popup already moved on

I have tried the followings:

  1. Adding await to the message sending
  2. Using Promise.all
  3. Wrapping the response in Promise.resolve()

Why isn't the await waiting for the background script to complete, and how can I properly handle this async communication between popup and background script?

NOTE: The extension is created using WXT framework

7
  • 1
    Are you really trying to send a message from the popup script to the background script, from the background script to the content script, from content script to background script, from background script back to popup script? Commented Apr 3 at 3:11
  • From the documentation: "Warning: Do not prepend async to the function. Prepending async changes the meaning to sending an asynchronous response using a promise, which is effectively the same as sendResponse(true)." Commented Apr 3 at 3:49
  • If this runs in Chrome, it can't use async onMessage listener (more info). Otherwise, 1) use browser.tabs.sendMessage inside the popup, no need for the background script here; 2) re-inject files from content_scripts after reloading/installing the extension in Chrome. Commented Apr 3 at 4:50
  • @guest271314 Yes, all of this happens based on different conditions and situations. Commented Apr 3 at 5:59
  • @Nanigashi Then how should i write it? This is my first time writing a browser extension. So I went with what was actually working from multiple sources. So if i remove the async and await then i believe all of my functions also need to be synchronous right? Commented Apr 3 at 6:00

1 Answer 1

0

The following v3 example demonstrates sending a message from a popup script directly to a content script (tested in Firefox). Everything is asynchronous.

Separate messages would be required to and from the background script, if desired.

manifest.json

{
  "manifest_version": 3,
  "name": "Answer",
  "description": "Answer a Stack Overflow question",
  "version": "0.1",
  "action": {
    "default_popup": "popup.htm",
    "default_title": "answer"
  },
  "content_scripts": [ {
    "js": [ "content.js" ],
    "matches": [ "<all_urls>" ],
    "match_about_blank": true
  } ],
  "permissions": [
    "activeTab"
  ]
}

content.js

( function () {
  'use strict';

  // receive null message from popup and reply with assorted dimensions
  function onMessage( _m, _s, sendResponse ) {
    sendResponse( {
      width: Math.max( document.documentElement.scrollWidth, document.body.scrollWidth ),
      height: Math.max( document.documentElement.scrollHeight, document.body.scrollHeight ),
      viewportHeight: window.innerHeight,
      originalScroll: window.scrollY
    } );
  }
  browser.runtime.onMessage.addListener( onMessage );
} () );

popup.htm

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Answer</title>
  </head>
  <body>
    <table><tbody>
      <tr><td>W:</td><td id="w"></td></tr>
      <tr><td>H:</td><td id="h"></td></tr>
      <tr><td>VH:</td><td id="vh"></td></tr>
      <tr><td>SY:</td><td id="sy"></td></tr>
    </tbody></table>
  </body>
  <script src="popup.js"></script>
</html>

popup.js

( function () {
  'use strict';

  // display the reply from the active tab
  function displayHW( reply ) {
    document.getElementById( 'w' ).textContent = reply.width;
    document.getElementById( 'h' ).textContent = reply.height;
    document.getElementById( 'vh' ).textContent = reply.viewportHeight;
    document.getElementById( 'sy' ).textContent = reply.originalScroll;
  }

  // just send the message first thing
  browser.tabs.query( {
    active: true,
    currentWindow: true
  } ).then( function ( tabs ) {
    browser.tabs.sendMessage(
      tabs[ 0 ].id,
      null // the simplest message is nothing
    ).then( displayHW );
  } );
} () );
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.