Oak_xo
Oak_xo

Reputation: 45

How can I set global variables in chrome extension

I work on a chrome extension which has a const user that is set in the first lines of the background.js, when I change its values and use them later in a different function they always return to their set values in the beginning.

I read online about hoisting and that it is to source of the problem but how can I avoid it so i can actually manipulate the variables and use them later on with no problem.

I also saw the use of globalThis but when i tried to call or set the values in the functions with globalThis it didn't work as well.

Here is my first lines of background.js:

var user={
connection:undefined,
id:"id",
username:"username",
room:["id","password","url","tabid","ishost"],
room_members:[],
in_room:false,
room_process:[false,"intervelId"],
current_tab:["url","id"]

}

I also tried working with globalThis when setting some of the values of user like showen here:

function connect(){
   globalThis.user.connection = new WebSocket('ws://192.168.3.16:8765'); 
   globalThis.user.connection.onopen = function(e) {
     globalThis.user.connection.send("get_id");
   };
   globalThis.user.connection.onmessage=function(event){
      let data=event.data.split(',');
    
      let temp_i=data[0]
      globalThis.user.id=temp_i;

      let temp_u=data[1]
      globalThis.user.username=temp_u;
    
    console.log("connection: ",user.id,",",user.username);
   };    
   
}

and for example if I got from the last function that user.id="Oak" when I try to recall the value in a different function like this:

function test(){
   console.log(user.id);
}

it shows "id" and not "Oak"

EDIT

I tried to use the storage.local by putting the var user in the onInstalled event of the program and then by having two functions I can get the current value of user out of the local storage and then update it as well.

here is my code:

first init of the var user:

chrome.runtime.onInstalled.addListener(async () => {
//opens welcome page
let url = chrome.runtime.getURL("htmls/hello.html");

let tab = await chrome.tabs.create({ url });

//setting up the user var in chrome's local storage

chrome.storage.local.get(['userLocal'], async function (result) {

    var user={
        connection:undefined,
        id:"id",
        username:"username",
        room:["id","password","url","tabid","ishost"],
        room_members:[],
        in_room:false,
        room_process:[false,"intervelId"],
        current_tab:["url","id"]
        }
    chrome.storage.local.set({userLocal: user}, function () {}); // save it in local.
    
});

//connect to server and recive id 
connect()

});

the two functions function:

function get_user(){
chrome.storage.local.get(['userLocal'], async function (result) {
    var userLocal = result.userLocal;
    return userLocal;
});

}

function update_user(tmp_user){
chrome.storage.local.get(['userLocal'], async function (result) {
    var userLocal = tmp_user;
    chrome.storage.local.set({userLocal: userLocal}, function () {}); // save it in local.
    return userLocal;
});  

}

and for example if I use what I've written:

function connect(){

var user=get_user();

user.connection = new WebSocket('ws://192.168.3.16:8765'); //'ws://192.168.3.16:8765'
user=update_user(user);

}

I get this error: "Uncaught (in promise) TypeError: Cannot set properties of undefined (setting 'connection')"

Upvotes: 1

Views: 4976

Answers (1)

relentless
relentless

Reputation: 493

The problem is that a background service worker is loaded when it is needed, and unloaded when it goes idle. So, after a few seconds of being idle, the background script unloads itself, making you lose the changes you made to the user object.

You could save the user object in chrome.storage.local, and then read and modify from there. Something like this:

// background.js; "initial lines" =>

chrome.storage.local.get(['userLocal'], async function (result) {
let userLocal = result.userLocal
if (userLocal === undefined) {
    // it means there was nothing before. This way you don't overwrite
    // the user object every time the backgorund.js loads.
    var user={
        connection:undefined,
        id:"id",
        username:"username",
        room:["id","password","url","tabid","ishost"],
        room_members:[],
        in_room:false,
        room_process:[false,"intervelId"],
        current_tab:["url","id"]
        }
    chrome.storage.local.set({userLocal: user}, function () {}); // save it in local.
}})

When you want to modify the user, you retrieve it from local and modify the result before saving it back in the localStorage.

// example of modifying a property =>

chrome.storage.local.get(['userLocal'], async function (result) {
let userLocal = result.userLocal
if (userLocal !== undefined) {
    userLocal.connection = new WebSocket('ws://192.168.3.16:8765');
    // ...

    chrome.storage.local.set({userLocal: userLocal}, function () {}); // save it in local.
}})

You can also just read the user properties, without modifying them and saving them back to the localStorage.

############ EDIT:

because chrome.storage.local is asynchronous, try to transform you code like this:

async function get_user(){
    return new Promise(async function (res, rej) {
      chrome.storage.local.get(['userLocal'], async function (result) {
          var userLocal = result.userLocal;
          res(userLocal);
      });
    });
}

var user= await get_user(); // call it like this.

Upvotes: 4

Related Questions