title: Communication between background scripts and content script in a loop
body: <p>I'm developing a chrome extension that : </p>
  
  <ul>
  <li>opens a "panel" with a button</li>
  <li>when you click the button, a new tab is created</li>
  <li>then in this new tab, I loop through an array of urls to retrieve informations on each url</li>
  </ul>
  
  <p>For these actions, I'm using Promises, because I think it's the way to do :)</p>
  
  <p><strong>background.js</strong></p>
  
  <pre><code>chrome.browserAction.onClicked.addListener(function (tab) {
      var tabUrl = tab.url;
      originalWindowId = tab.windowId;
      var popupURL = chrome.runtime.getURL("extension/main_panel.html");
      chrome.windows.create({
          url: popupURL,
          type: 'panel',
          width: 600,
          height: 520
      }, function (window) {
          extensionWindowId = window.id;
      });
  });
  
  function createNewTab() {
      return new Promise(function (resolve, reject) {
          chrome.tabs.create({
              url: "about:blank"
          }, function (tab) {
              console.log("tab created with id " + tab.id);
              resolve(tab.id);
          });
      });
  }
  
  function updateNewTab(newTabId, url) {
      return new Promise(function (resolve, reject) {
          chrome.tabs.update(newTabId, {
              url: url
          }, function (tab) {
              console.log("tab with id " + tab.id + " updated");
              chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
                  if (changeInfo.status === 'complete') {
                      console.log("tab with id " + tab.id + " and url " + url + " updated complete");
                      chrome.tabs.sendMessage(tab.id, {
                          action: "getATitle"
                      }, function (response) {
                          if (response.data != "") {
                              resolve(response.data);
                          } else
                              reject("failed");
                      });
                  }
              });
          });
      });
  }
  </code></pre>
  
  <p><strong>main_panel.js</strong></p>
  
  <pre><code>var urls = ["https://forum.openstreetmap.fr/viewtopic.php?f=3&amp;t=6811&amp;start=0", "https://forum.openstreetmap.fr/viewtopic.php?f=3&amp;t=6811&amp;start=25"];
  const j = urls.length;
  
  var background = chrome.extension.getBackgroundPage();
  
  var scrapButton = document.getElementById("scrap_button");
  scrapButton.addEventListener("click", function () {
      background.
      createNewTab()
          .then(function (newTabId) {
              console.log("response : newTabId " + newTabId);
              var all = []; 
              for (let i = 0; i &lt; j; i ++) {
                  console.log("try with i = " + i + " | url = " + urls[i]);
                  var p = background.updateNewTab(newTabId, urls[i]);
                  all.push(p);
              }
              return Promise.all(all);
          })
          .then(function (values) {
              console.log(values);
          })
  
  });
  </code></pre>
  
  <p><strong>content.js</strong></p>
  
  <pre><code>chrome.runtime.onMessage.addListener(
      function (request, sender, sendResponse) {
          console.log("request from bg : " + request.action + " | url = " + location.href);
          if (request.action == "getATitle") {
              var title = $("h3.first a").text();
              console.log("title = " + title);
              sendResponse({
                  data: title
              });
          }
      }
  );
  </code></pre>
  
  <p>So my problem is that I retrieve twice the result from the second url, not from the first. I think it's a (a)synchronous issue but wich one ?</p>
  
  <p>Thanks !</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>So thanks to wOxxOm who drove me on the right way !</p>
  
  <p>But it's still not totally ok : I success to retrieve informations on each url, one after one, and from the "panel" side, all is fine. </p>
  
  <p>But in background side, after it received response from content side for the first url, it updates the tab with second url, but chrome.tabs.onUpdated.addListener send the message 2 times, one with the first url, one with the second, and in response, content send 2 times its informations.
  I think of a listener problem : maybe I have to remove it after each update ?</p>
  
  <p>I don't know if I am very clear ... Here's a picture of console : </p>
  
  <p><a href="https://i.stack.imgur.com/QqZxs.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/QqZxs.png" alt="console log of background.js"></a></p>
  
  <p>And here's the new code of main_panel.js</p>
  
  <pre><code>var background = chrome.extension.getBackgroundPage();
  
  var scrapButton = document.getElementById("scrap_button");
  scrapButton.addEventListener("click", function () {
      background.
      createNewTab()
          .then(function (newTabId) {
              console.log("response : newTabId " + newTabId);
              return processUrls(newTabId);
          })
  });
  
  async function delayedUpdate(newTabId, url, response) {
      const data = await background.updateNewTab(newTabId, url);
      console.log("data : " + data);
  }
  
  async function processUrls(newTabId) {
      for (const url of urls) {
          console.log("try with url = " + url);
          await delayedUpdate(newTabId, url);
      }
      console.log('Done!');
  }
  </code></pre>
  
  <p><strong>EDIT 2</strong></p>
  
  <p>So thanks to wOxxOm who helped me to accomplish the final code for background.js :</p>
  
  <pre><code>function updateNewTab(newTabId, url) {
      return new Promise(function (resolve, reject) {
          chrome.tabs.update(newTabId, {
              url: url
          }, function (tab) {
              console.log("tab with id " + tab.id + " updated");
              chrome.tabs.onUpdated.addListener(function tabUpdatedListener(tabId, changeInfo, tab) {
                  if (changeInfo.status === 'complete') {
                      console.log("tab with id " + tab.id + " and url " + url + " updated complete");
                      chrome.tabs.sendMessage(tab.id, {
                          action: "getATitle"
                      }, function (response) {
                          console.log("data received in bg : " + response.data);
                          if (response.data != "") {
                              resolve(response.data);
                   chrome.tabs.onUpdated.removeListener(tabUpdatedListener);
                          } else
                              reject("failed");
                      });
                  }
              });
          });
      });
  }
  </code></pre>