How to share a unique tab ID between content and background scripts without an asynchronous delay?











up vote
0
down vote

favorite












I have built a chrome extension and I'm getting hit by a race condition that I need help with.



If you see the answer chrome extension: sharing an object between content scripts and background script it tells us that you cannot share a variable between content and background scripts.



My goal is to generate a unique ID per-browser tab and then share it in between the content.js and the background.js. Then I need to use this value in a content injected javascript as explained in this answer: In Chrome extensions, can you force some javascript to be injected before everything?



The only way I have been able to figure out how to do this is by doing the following async code then I just use the tab ID as the unique ID:



content.js



await pingBackground();
async function pingBackground() {
var info;
await new Promise(function (resolve, reject) {
chrome.runtime.sendMessage({ type: 1 }, function (response) {
if (response !== undefined) {
info = response;
resolve();
}
else {
reject();
}
});
});
console.log("Id is " + info.id);
}


background.js



chrome.runtime.onMessage.addListener(messageHandler);
function messageHandler(message, sender, reply) {
switch (message.type) {
case 1:
reply({ 'id': sender['tab'].id, 'active': true });
break;
}
}


manifest.json



{
"name": "oogi",
"version": "0.1",
"manifest_version": 2,
"background": {
"scripts": [
"common.js",
"background.js"
],
"persistent": true
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"],
"run_at": "document_start"
}
],
"permissions": [
"contentSettings",
"webRequest",
"webRequestBlocking",
"*://*/*"
]
}


But the problem with this is by the time I get the tab ID from background js, the script's content has already been loaded.



Is there some way to make it so this variable can be asynchronously shared between background.js and content.js? Or is this simply impossible?



Can I switch it around and have background.js load a variable from content.js asynchronously?



UPDATE:



A terrible hack which works is to do this in the foreground of the content.js:



var sleepScript = document.createElement('script');
var sleepCode = `function sleep (ms) {
var start = new Date().getTime();
while (new Date() < start + ms) {}
return 0;
}
sleep(500);`;
sleepScript.textContent = sleepCode;
(document.head || document.documentElement).appendChild(sleepScript);


This will force the page to wait for a bit giving the time to query the background before running the inline dom.



It works but that's awful.










share|improve this question
























  • You can share it by setting an http cookie header in your background script using webRequest API in blocking mode. The cookie will be available via document.cookie in your content script. I believe I saw an answer for that by Xan. If the value is big you can additionally use blob + synchronous XHR (Tampermonkey does that).
    – wOxxOm
    Nov 6 at 4:36










  • Found it: Injecting javascript variable before content script
    – wOxxOm
    Nov 6 at 5:06










  • You are definitely my favorite person. I would have never figured this out. It worked like a charm.
    – Nicholas DiPiazza
    Nov 6 at 5:38












  • Darn. Show-stopper on this one for me is that I need it to work in multiple tabs. As soon as one of my tabs opens this up, bam I'm stuck with it.
    – Nicholas DiPiazza
    Nov 6 at 5:52












  • The problem is the seed value that it creates is created in the background.js foreground which is once per browser window. So now every page is using that same seed value. What I really need is the Tab ID in the content.js page of the tab that it belongs to, or some seed value set per tab to achieve the same thing.
    – Nicholas DiPiazza
    Nov 6 at 6:03















up vote
0
down vote

favorite












I have built a chrome extension and I'm getting hit by a race condition that I need help with.



If you see the answer chrome extension: sharing an object between content scripts and background script it tells us that you cannot share a variable between content and background scripts.



My goal is to generate a unique ID per-browser tab and then share it in between the content.js and the background.js. Then I need to use this value in a content injected javascript as explained in this answer: In Chrome extensions, can you force some javascript to be injected before everything?



The only way I have been able to figure out how to do this is by doing the following async code then I just use the tab ID as the unique ID:



content.js



await pingBackground();
async function pingBackground() {
var info;
await new Promise(function (resolve, reject) {
chrome.runtime.sendMessage({ type: 1 }, function (response) {
if (response !== undefined) {
info = response;
resolve();
}
else {
reject();
}
});
});
console.log("Id is " + info.id);
}


background.js



chrome.runtime.onMessage.addListener(messageHandler);
function messageHandler(message, sender, reply) {
switch (message.type) {
case 1:
reply({ 'id': sender['tab'].id, 'active': true });
break;
}
}


manifest.json



{
"name": "oogi",
"version": "0.1",
"manifest_version": 2,
"background": {
"scripts": [
"common.js",
"background.js"
],
"persistent": true
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"],
"run_at": "document_start"
}
],
"permissions": [
"contentSettings",
"webRequest",
"webRequestBlocking",
"*://*/*"
]
}


But the problem with this is by the time I get the tab ID from background js, the script's content has already been loaded.



Is there some way to make it so this variable can be asynchronously shared between background.js and content.js? Or is this simply impossible?



Can I switch it around and have background.js load a variable from content.js asynchronously?



UPDATE:



A terrible hack which works is to do this in the foreground of the content.js:



var sleepScript = document.createElement('script');
var sleepCode = `function sleep (ms) {
var start = new Date().getTime();
while (new Date() < start + ms) {}
return 0;
}
sleep(500);`;
sleepScript.textContent = sleepCode;
(document.head || document.documentElement).appendChild(sleepScript);


This will force the page to wait for a bit giving the time to query the background before running the inline dom.



It works but that's awful.










share|improve this question
























  • You can share it by setting an http cookie header in your background script using webRequest API in blocking mode. The cookie will be available via document.cookie in your content script. I believe I saw an answer for that by Xan. If the value is big you can additionally use blob + synchronous XHR (Tampermonkey does that).
    – wOxxOm
    Nov 6 at 4:36










  • Found it: Injecting javascript variable before content script
    – wOxxOm
    Nov 6 at 5:06










  • You are definitely my favorite person. I would have never figured this out. It worked like a charm.
    – Nicholas DiPiazza
    Nov 6 at 5:38












  • Darn. Show-stopper on this one for me is that I need it to work in multiple tabs. As soon as one of my tabs opens this up, bam I'm stuck with it.
    – Nicholas DiPiazza
    Nov 6 at 5:52












  • The problem is the seed value that it creates is created in the background.js foreground which is once per browser window. So now every page is using that same seed value. What I really need is the Tab ID in the content.js page of the tab that it belongs to, or some seed value set per tab to achieve the same thing.
    – Nicholas DiPiazza
    Nov 6 at 6:03













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have built a chrome extension and I'm getting hit by a race condition that I need help with.



If you see the answer chrome extension: sharing an object between content scripts and background script it tells us that you cannot share a variable between content and background scripts.



My goal is to generate a unique ID per-browser tab and then share it in between the content.js and the background.js. Then I need to use this value in a content injected javascript as explained in this answer: In Chrome extensions, can you force some javascript to be injected before everything?



The only way I have been able to figure out how to do this is by doing the following async code then I just use the tab ID as the unique ID:



content.js



await pingBackground();
async function pingBackground() {
var info;
await new Promise(function (resolve, reject) {
chrome.runtime.sendMessage({ type: 1 }, function (response) {
if (response !== undefined) {
info = response;
resolve();
}
else {
reject();
}
});
});
console.log("Id is " + info.id);
}


background.js



chrome.runtime.onMessage.addListener(messageHandler);
function messageHandler(message, sender, reply) {
switch (message.type) {
case 1:
reply({ 'id': sender['tab'].id, 'active': true });
break;
}
}


manifest.json



{
"name": "oogi",
"version": "0.1",
"manifest_version": 2,
"background": {
"scripts": [
"common.js",
"background.js"
],
"persistent": true
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"],
"run_at": "document_start"
}
],
"permissions": [
"contentSettings",
"webRequest",
"webRequestBlocking",
"*://*/*"
]
}


But the problem with this is by the time I get the tab ID from background js, the script's content has already been loaded.



Is there some way to make it so this variable can be asynchronously shared between background.js and content.js? Or is this simply impossible?



Can I switch it around and have background.js load a variable from content.js asynchronously?



UPDATE:



A terrible hack which works is to do this in the foreground of the content.js:



var sleepScript = document.createElement('script');
var sleepCode = `function sleep (ms) {
var start = new Date().getTime();
while (new Date() < start + ms) {}
return 0;
}
sleep(500);`;
sleepScript.textContent = sleepCode;
(document.head || document.documentElement).appendChild(sleepScript);


This will force the page to wait for a bit giving the time to query the background before running the inline dom.



It works but that's awful.










share|improve this question















I have built a chrome extension and I'm getting hit by a race condition that I need help with.



If you see the answer chrome extension: sharing an object between content scripts and background script it tells us that you cannot share a variable between content and background scripts.



My goal is to generate a unique ID per-browser tab and then share it in between the content.js and the background.js. Then I need to use this value in a content injected javascript as explained in this answer: In Chrome extensions, can you force some javascript to be injected before everything?



The only way I have been able to figure out how to do this is by doing the following async code then I just use the tab ID as the unique ID:



content.js



await pingBackground();
async function pingBackground() {
var info;
await new Promise(function (resolve, reject) {
chrome.runtime.sendMessage({ type: 1 }, function (response) {
if (response !== undefined) {
info = response;
resolve();
}
else {
reject();
}
});
});
console.log("Id is " + info.id);
}


background.js



chrome.runtime.onMessage.addListener(messageHandler);
function messageHandler(message, sender, reply) {
switch (message.type) {
case 1:
reply({ 'id': sender['tab'].id, 'active': true });
break;
}
}


manifest.json



{
"name": "oogi",
"version": "0.1",
"manifest_version": 2,
"background": {
"scripts": [
"common.js",
"background.js"
],
"persistent": true
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"],
"run_at": "document_start"
}
],
"permissions": [
"contentSettings",
"webRequest",
"webRequestBlocking",
"*://*/*"
]
}


But the problem with this is by the time I get the tab ID from background js, the script's content has already been loaded.



Is there some way to make it so this variable can be asynchronously shared between background.js and content.js? Or is this simply impossible?



Can I switch it around and have background.js load a variable from content.js asynchronously?



UPDATE:



A terrible hack which works is to do this in the foreground of the content.js:



var sleepScript = document.createElement('script');
var sleepCode = `function sleep (ms) {
var start = new Date().getTime();
while (new Date() < start + ms) {}
return 0;
}
sleep(500);`;
sleepScript.textContent = sleepCode;
(document.head || document.documentElement).appendChild(sleepScript);


This will force the page to wait for a bit giving the time to query the background before running the inline dom.



It works but that's awful.







javascript google-chrome-extension






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 5 at 21:58

























asked Nov 5 at 19:38









Nicholas DiPiazza

3,37853472




3,37853472












  • You can share it by setting an http cookie header in your background script using webRequest API in blocking mode. The cookie will be available via document.cookie in your content script. I believe I saw an answer for that by Xan. If the value is big you can additionally use blob + synchronous XHR (Tampermonkey does that).
    – wOxxOm
    Nov 6 at 4:36










  • Found it: Injecting javascript variable before content script
    – wOxxOm
    Nov 6 at 5:06










  • You are definitely my favorite person. I would have never figured this out. It worked like a charm.
    – Nicholas DiPiazza
    Nov 6 at 5:38












  • Darn. Show-stopper on this one for me is that I need it to work in multiple tabs. As soon as one of my tabs opens this up, bam I'm stuck with it.
    – Nicholas DiPiazza
    Nov 6 at 5:52












  • The problem is the seed value that it creates is created in the background.js foreground which is once per browser window. So now every page is using that same seed value. What I really need is the Tab ID in the content.js page of the tab that it belongs to, or some seed value set per tab to achieve the same thing.
    – Nicholas DiPiazza
    Nov 6 at 6:03


















  • You can share it by setting an http cookie header in your background script using webRequest API in blocking mode. The cookie will be available via document.cookie in your content script. I believe I saw an answer for that by Xan. If the value is big you can additionally use blob + synchronous XHR (Tampermonkey does that).
    – wOxxOm
    Nov 6 at 4:36










  • Found it: Injecting javascript variable before content script
    – wOxxOm
    Nov 6 at 5:06










  • You are definitely my favorite person. I would have never figured this out. It worked like a charm.
    – Nicholas DiPiazza
    Nov 6 at 5:38












  • Darn. Show-stopper on this one for me is that I need it to work in multiple tabs. As soon as one of my tabs opens this up, bam I'm stuck with it.
    – Nicholas DiPiazza
    Nov 6 at 5:52












  • The problem is the seed value that it creates is created in the background.js foreground which is once per browser window. So now every page is using that same seed value. What I really need is the Tab ID in the content.js page of the tab that it belongs to, or some seed value set per tab to achieve the same thing.
    – Nicholas DiPiazza
    Nov 6 at 6:03
















You can share it by setting an http cookie header in your background script using webRequest API in blocking mode. The cookie will be available via document.cookie in your content script. I believe I saw an answer for that by Xan. If the value is big you can additionally use blob + synchronous XHR (Tampermonkey does that).
– wOxxOm
Nov 6 at 4:36




You can share it by setting an http cookie header in your background script using webRequest API in blocking mode. The cookie will be available via document.cookie in your content script. I believe I saw an answer for that by Xan. If the value is big you can additionally use blob + synchronous XHR (Tampermonkey does that).
– wOxxOm
Nov 6 at 4:36












Found it: Injecting javascript variable before content script
– wOxxOm
Nov 6 at 5:06




Found it: Injecting javascript variable before content script
– wOxxOm
Nov 6 at 5:06












You are definitely my favorite person. I would have never figured this out. It worked like a charm.
– Nicholas DiPiazza
Nov 6 at 5:38






You are definitely my favorite person. I would have never figured this out. It worked like a charm.
– Nicholas DiPiazza
Nov 6 at 5:38














Darn. Show-stopper on this one for me is that I need it to work in multiple tabs. As soon as one of my tabs opens this up, bam I'm stuck with it.
– Nicholas DiPiazza
Nov 6 at 5:52






Darn. Show-stopper on this one for me is that I need it to work in multiple tabs. As soon as one of my tabs opens this up, bam I'm stuck with it.
– Nicholas DiPiazza
Nov 6 at 5:52














The problem is the seed value that it creates is created in the background.js foreground which is once per browser window. So now every page is using that same seed value. What I really need is the Tab ID in the content.js page of the tab that it belongs to, or some seed value set per tab to achieve the same thing.
– Nicholas DiPiazza
Nov 6 at 6:03




The problem is the seed value that it creates is created in the background.js foreground which is once per browser window. So now every page is using that same seed value. What I really need is the Tab ID in the content.js page of the tab that it belongs to, or some seed value set per tab to achieve the same thing.
– Nicholas DiPiazza
Nov 6 at 6:03












1 Answer
1






active

oldest

votes

















up vote
0
down vote



accepted










This question was already answered previously, although it is hard to tell that this is the same issue at first glance.



https://stackoverflow.com/a/45105934



The answer is pretty descriptive so give it a read.



Here is the script changes that make it work:



// background.js
function addSeedCookie(details) {
details.responseHeaders.push({
name: "Set-Cookie",
value: `tab_id=${details.tabId}; Max-Age=2`
});
return {
responseHeaders: details.responseHeaders
};
}

chrome.webRequest.onHeadersReceived.addListener(
addSeedCookie, {urls: ["<all_urls>"]}, ["blocking", "responseHeaders"]
);

// inject.js
function getCookie(cookie) { // https://stackoverflow.com/a/19971550/934239
return document.cookie.split(';').reduce(function(prev, c) {
var arr = c.split('=');
return (arr[0].trim() === cookie) ? arr[1] : prev;
}, undefined);
}

var tabId = getCookie("tab_id");





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53161083%2fhow-to-share-a-unique-tab-id-between-content-and-background-scripts-without-an-a%23new-answer', 'question_page');
    }
    );

    Post as a guest
































    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    0
    down vote



    accepted










    This question was already answered previously, although it is hard to tell that this is the same issue at first glance.



    https://stackoverflow.com/a/45105934



    The answer is pretty descriptive so give it a read.



    Here is the script changes that make it work:



    // background.js
    function addSeedCookie(details) {
    details.responseHeaders.push({
    name: "Set-Cookie",
    value: `tab_id=${details.tabId}; Max-Age=2`
    });
    return {
    responseHeaders: details.responseHeaders
    };
    }

    chrome.webRequest.onHeadersReceived.addListener(
    addSeedCookie, {urls: ["<all_urls>"]}, ["blocking", "responseHeaders"]
    );

    // inject.js
    function getCookie(cookie) { // https://stackoverflow.com/a/19971550/934239
    return document.cookie.split(';').reduce(function(prev, c) {
    var arr = c.split('=');
    return (arr[0].trim() === cookie) ? arr[1] : prev;
    }, undefined);
    }

    var tabId = getCookie("tab_id");





    share|improve this answer



























      up vote
      0
      down vote



      accepted










      This question was already answered previously, although it is hard to tell that this is the same issue at first glance.



      https://stackoverflow.com/a/45105934



      The answer is pretty descriptive so give it a read.



      Here is the script changes that make it work:



      // background.js
      function addSeedCookie(details) {
      details.responseHeaders.push({
      name: "Set-Cookie",
      value: `tab_id=${details.tabId}; Max-Age=2`
      });
      return {
      responseHeaders: details.responseHeaders
      };
      }

      chrome.webRequest.onHeadersReceived.addListener(
      addSeedCookie, {urls: ["<all_urls>"]}, ["blocking", "responseHeaders"]
      );

      // inject.js
      function getCookie(cookie) { // https://stackoverflow.com/a/19971550/934239
      return document.cookie.split(';').reduce(function(prev, c) {
      var arr = c.split('=');
      return (arr[0].trim() === cookie) ? arr[1] : prev;
      }, undefined);
      }

      var tabId = getCookie("tab_id");





      share|improve this answer

























        up vote
        0
        down vote



        accepted







        up vote
        0
        down vote



        accepted






        This question was already answered previously, although it is hard to tell that this is the same issue at first glance.



        https://stackoverflow.com/a/45105934



        The answer is pretty descriptive so give it a read.



        Here is the script changes that make it work:



        // background.js
        function addSeedCookie(details) {
        details.responseHeaders.push({
        name: "Set-Cookie",
        value: `tab_id=${details.tabId}; Max-Age=2`
        });
        return {
        responseHeaders: details.responseHeaders
        };
        }

        chrome.webRequest.onHeadersReceived.addListener(
        addSeedCookie, {urls: ["<all_urls>"]}, ["blocking", "responseHeaders"]
        );

        // inject.js
        function getCookie(cookie) { // https://stackoverflow.com/a/19971550/934239
        return document.cookie.split(';').reduce(function(prev, c) {
        var arr = c.split('=');
        return (arr[0].trim() === cookie) ? arr[1] : prev;
        }, undefined);
        }

        var tabId = getCookie("tab_id");





        share|improve this answer














        This question was already answered previously, although it is hard to tell that this is the same issue at first glance.



        https://stackoverflow.com/a/45105934



        The answer is pretty descriptive so give it a read.



        Here is the script changes that make it work:



        // background.js
        function addSeedCookie(details) {
        details.responseHeaders.push({
        name: "Set-Cookie",
        value: `tab_id=${details.tabId}; Max-Age=2`
        });
        return {
        responseHeaders: details.responseHeaders
        };
        }

        chrome.webRequest.onHeadersReceived.addListener(
        addSeedCookie, {urls: ["<all_urls>"]}, ["blocking", "responseHeaders"]
        );

        // inject.js
        function getCookie(cookie) { // https://stackoverflow.com/a/19971550/934239
        return document.cookie.split(';').reduce(function(prev, c) {
        var arr = c.split('=');
        return (arr[0].trim() === cookie) ? arr[1] : prev;
        }, undefined);
        }

        var tabId = getCookie("tab_id");






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 6 at 14:21

























        answered Nov 6 at 13:53









        Nicholas DiPiazza

        3,37853472




        3,37853472






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53161083%2fhow-to-share-a-unique-tab-id-between-content-and-background-scripts-without-an-a%23new-answer', 'question_page');
            }
            );

            Post as a guest




















































































            這個網誌中的熱門文章

            Xamarin.form Move up view when keyboard appear

            Post-Redirect-Get with Spring WebFlux and Thymeleaf

            Anylogic : not able to use stopDelay()