Reputation: 45
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
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