0

Below is an attempt to extract some information from a webpage and then display it on a Chrome extension page.

The problem I have based on many hours of research seems to be that the sending of variable extracted from webpage to extension page failed as my extractor is asynchronous.

The variable that arrives at my extension page after the last step below is [object object].

It seems that the sendMessage action doesn't wait for async-wait step to finish before sending results to the receiving end. I have tried many fixes from Stack Overflow answers, but I just don't seem to find a solution.

1.) This code will run on the webpage to extract some information (the async await is needed in original code, and the below is just a sample).

async function Extractor(document) {
    var item = document.getElementbyId("....");
    await new Promise(r => setTimeout(r, 3000));

    return item
}

2.) I assume this code sends the message to the one below telling it to run and retrieve extractor results.

chrome.runtime.sendMessage({
    action: "getSource",
    source: Extractor(document)
});

3.) This code is in popup.js, where my intention is to insert the extractor's result from webpage into a popup.html extension page, under node id = "message".

chrome.runtime.onMessage.addListener(function(request, sender) {
   if (request.action == "getSource") {
      message.innerText = request.source;
   }
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Milleon
  • 35
  • 6
  • 2
    You can't send a DOM element, you can send its `textContent` or `innerHTML` properties. – wOxxOm Oct 14 '22 at 17:13
  • Thanks for the reply, I have tested that and still it doens't work. Only when I remove the asycronous method it works. So I am quite sure the issue is with that..? – Milleon Oct 14 '22 at 21:18
  • That bug was that his code doesn't run. I think for mine, it runs, but the coordination is wrong. The sendMessage action doesn't wait for the async-wait function to finish before sending results to the receiving end. – Milleon Oct 14 '22 at 21:54
  • Ah, indeed, you need to add `await` before calling Extractor. And you should probably use executeScript as explained here: [How to access the webpage DOM rather than the extension page DOM?](https://stackoverflow.com/q/4532236) – wOxxOm Oct 14 '22 at 21:59
  • The returned item result in step 1 is fine. The issue seems to be Step 2 & Step 3. – Milleon Oct 14 '22 at 22:15
  • No, messaging can't send DOM elements. – wOxxOm Oct 15 '22 at 07:52

1 Answers1

1

This sample displays document.title in a popup.

File popup.js

const message = document.getElementById("message");

chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
  chrome.scripting.executeScript({
    target: { tabId: tabs[0].id },
    function: getDocumentTitle
  });
});

async function getDocumentTitle() {
  chrome.runtime.sendMessage({
    action: "getSource",
    source: await Extractor()
  });

  async function Extractor() {
    var item = document.title;
    await new Promise(r => setTimeout(r, 3000));

    return item;
  }
}

chrome.runtime.onMessage.addListener(function (request, sender) {
  if (request.action == "getSource") {
    message.innerText = request.source;
  }
});

File manifest.json

{
  "name": "getDocumentTitle",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": [
    "scripting"
  ],
  "host_permissions": [
    "<all_urls>"
  ],
  "action": {
    "default_popup": "popup.html"
  }
}

File popup.html

<!DOCTYPE html>
<html>

<body>
  <div id="message"></div>
  <script src="popup.js"></script>
</body>

</html>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Norio Yamamoto
  • 1,495
  • 2
  • 3
  • 10
  • Thanks so much @Norio Yamamoto!! This solved the issue. Key part was to implement this correctly: async function getDocumentTitle() { chrome.runtime.sendMessage({ action: "getSource", source: await Extractor() }); async function Extractor() { var item = document.title; await new Promise(r => setTimeout(r, 3000)); return item; } } – Milleon Oct 15 '22 at 11:39