Почему всплывающий скрипт посылает больше сообщения в контентный скрипт, когда всплывающее окно открывается снова? - PullRequest
0 голосов
/ 01 января 2019

У меня Firefox webextension.В popup.html у меня есть кнопка, и, нажав на нее, popup.js отправляет сообщение на content.js.Content.js получает сообщение и создает console.log с текстом «Сообщение из всплывающего окна».Если я снова нажму кнопку, действие повторяется.Проблема в том, что когда я щелкаю вне всплывающего окна, снова открываю всплывающее окно и снова нажимаю кнопку, потому что content.js получает два сообщения из popup.js и создает два console.log.Если я повторю это снова, content.js получит три сообщения и так далее.Сколько раз я снова открываю всплывающее окно, столько раз, сколько отправляется сообщение.

Я думаю, что проблема где-то в popup.js, но я не могу понять.

манифест.json:

{
    "manifest_version": 2,
    "name": "Extension",
    "version": "1.0",

    "description": "Firefox extension",

    "permissions": [
        "activeTab",
        "<all_urls>",
        "tabs"
    ],

    "browser_action": {
       "default_title": "Script",
       "default_popup": "popup.html"
    }
}

popup.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
  </head>
  <body>
    <button class="action">Start</button>
    <script src="popup.js"></script>
  </body>
</html>

popup.js:

browser.tabs.executeScript({file: "content.js"})
.then(listenForClicks)

function listenForClicks() { 
  document.addEventListener("click", (e) => {
    if (e.target.classList.contains("action")) {
      browser.tabs.query({active: true, currentWindow: true})
        .then(send)
    }
    function send(tabs) { 
      browser.tabs.sendMessage(tabs[0].id, {
          command: "message"
          });
      }
  });
}

content.js:

function handleMessage(request, sender, sendResponse) {
    if(request.command === "message"){
      console.log("Message from popup");
    }
}

browser.runtime.onMessage.addListener(handleMessage);

Ожидаемый результат заключается в том, что одним нажатием кнопки создается один файл console.log.Даже думал, что всплывающее окно открывалось несколько раз.

1 Ответ

0 голосов
/ 01 января 2019

Слушатели не удаляются сразу после закрытия всплывающего окна.Сборщик мусора занимает некоторое время, чтобы удалить его.

Если вы используете Firefox 50+, вы можете установить once в EventTarget.addEventListener () для слушателя, чтобы слушатель был удаленпосле первого раза.

Для более старых браузеров вы можете вручную удалить слушателя с помощью document.removeEventListener().

Теперь, если вы хотите, чтобы контент получал только ОДИН сообщение, вы можете удалить слушателя после первого раза, например:

Обновление после комментариев

popup.js:

// add event listener for the button (not the whole pop-up), to run ONCE only
document.querySelector('button.action').addEventListener('click', listener, {once: true}); // FF50+, Ch55+

async function listener() {

  await browser.tabs.executeScript({file: 'content.js'});
  const tabs = await browser.tabs.query({currentWindow: true, active: true});
  browser.tabs.sendMessage(tabs[0].id, {command: 'message'});
}

content.js:

// add listener only if it wasnt done before
if (!sessionStorage.getItem('runOnce')) {

  // keep track of previous attempts in sessionStorage
  sessionStorage.setItem('runOnce', 'true');      
  browser.runtime.onMessage.addListener(handleMessage);
}

function handleMessage(request, sender, sendResponse) {

  if(request.command === 'message'){
    console.log("Message from popup");

    // remove listern after the first run
    browser.runtime.onMessage.removeListener(handleMessage);
  }
}
...