Search code examples
google-chrome-extensionasync-awaitmessage-passingchrome-extension-manifest-v3

How to handle async requests when message passing within chrome extensions


Im building a chrome extension and need to get data from google cloud firestore in background.js before sending the returned data as a message to popup.js.

This is what background.js looks like:

  //background.js

  chrome.runtime.onMessage.addListener((msg, sender, resp) => {
    if (msg.command == 'fetch') {
      const listData = fetchListTitles();
      resp({
        type: 'result',
        status: 'success',
        data: listData,
        request: msg,
      });
      return true;
    }
  });
} catch (e) {
  console.error(e);
}

//get firestore data function
const fetchListTitles = async () => {
    let listTitles = [];
    const q = query(
      collectionGroup(db, 'Lists'),
      where('author', '==', 'placeholder')
    );

    const temp = await getDocs(q);

    temp.docs.map((doc) => {
      listTitles.push(linksToJSON(doc));
    });
    console.log(listTitles);
    return listTitles;
  };

This is what popup.js looks like

  //popup.js
  chrome.runtime.sendMessage({ command: 'fetch' }, (resp) => {
      if (resp.data) {
        console.log('popup', resp);
        setListTitles(resp.data);
      }
    });

When I read out or console.log the data returned, I do not see any data returned from friestore. However, in background.js I can see the returned data that I console.log from the fetchListTitles function


Solution

  • fetchListTitles is declared with async keyword which means it always returns a Promise.
    Chrome extensions can't send Promise via messaging.

    You need to send the response after the Promise is fullfilled:

    chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
      if (msg.command === 'fetch') {
        fetchListTitles().then(listData => sendResponse({
          type: 'result',
          status: 'success',
          data: listData,
          request: msg,
        }));
        return true; // keeps the channel open for sendResponse
      }
    });
    

    See also why Chrome extensions can't use async/await in onMessage directly.