英文:
Implementing singleton with vanilla JavaScript in frontend
问题
我有一个项目(纯粹的Web应用程序),我在使用Node.js路由器从后端提供HTML文件:
router.get("/", (req, res) => {
res.sendFile(views_dir + "index.html");
});
router.get("/login", (req, res) => {
res.sendFile(views_dir + "login.html");
});
并将JS文件作为静态文件提供app.use(express.static(path.join(__dirname, '/frontend')));
,其中/frontend
文件夹包含所有前端文件(包括HTML文件)。
现在,我有一个名为model.js
的文件(在frontend文件夹中),我正在尝试实现一个单例,用于保存所有页面通用的数据(例如用户当前是否已登录):
const Model = (function () {
let instance;
function init() {
let isLogged = false;
return {
getIsLogged: function () {
return isLogged;
},
setIsLogged: function (l) {
isLogged = l;
}
}
}
return {
getInstance: function () {
if (! instance) {
instance = init();
}
return instance;
}
}
})();
但是当用户被重定向时,似乎model.js
从后端再次被导入,覆盖了先前页面对模型的所有更改。
(假设我们在用户登录时将model
中的isLogged
变量更改为true
,然后重定向到'/'
,模型将被刷新并覆盖)
是否有办法只使用JavaScript实现这种要求?
我认为问题出在res.sendFile(views_dir + "index.html");
,它刷新了应用程序到新的状态,不会保存js文件的先前状态,是否有方法可以避免这种情况?只请求一次js文件?
英文:
I have a project ( vanilla web application ) where I serve html files from the backend using nodejs router:
router.get("/", (req, res) => {
res.sendFile(views_dir + "index.html");
});
router.get("/login", (req, res) => {
res.sendFile(views_dir + "login.html");
});
and serve the js files as static app.use(express.static(path.join(__dirname, '/frontend')));
where the /frontend
folder holds all the frontend files ( including the html files ).
Now, I have a file called model.js
( in frontend folder ) where I'm trying to implement a singleton that will hold data that is common to all pages ( such as if the user is currently logged or not ):
const Model = (function () {
let instance;
function init() {
let isLogged = false;
return {
getIsLogged: function () {
return isLogged;
},
setIsLogged: function (l) {
isLogged = l;
}
}
}
return {
getInstance: function () {
if (! instance) {
instance = init();
}
return instance;
}
}
})();
But when a user being redirected, seems like the model.js being imported all over again from the backend side, overriding all changes to the model from the previous page.
( Say we change the isLogged variable in the model to true when a user logged in, and redirecting to '/', the model being refreshed and overwritten )
Is there even a way to implement such a requirement with just JavaScript ?
I think the problem is with res.sendFile(views_dir + "index.html");
which refreshes the application to a new state and doesn't saves the previous state of the js files, is there a way to avoid this ? to request the js files just once ?
答案1
得分: 3
感谢@Jared的帮助解决了这个问题。
我使用localStorage来保存模型的当前状态,并在重定向到另一个页面时加载它。
const Model = (function () {
let instance;
let data = {
isLogged: false,
};
function init_localStorage() {
save_localStorage();
}
function load_localStorage() {
let model = JSON.parse(localStorage.getItem('Model'));
if (Object.keys(model).length === 0) {
init_localStorage();
}
data = model;
}
function save_localStorage() {
localStorage.setItem('Model', JSON.stringify(data));
}
function init() {
load_localStorage();
return {
getIsLogged: function () {
return data.isLogged;
},
setIsLogged: function (l) {
data.isLogged = l;
},
saveData: function () {
save_localStorage();
}
}
}
return {
getInstance: function () {
if (! instance) {
instance = init();
}
return instance;
}
}
})();
最终,我有两个主要的函数:save...
和 load...
用于读取/保存localStorage对象中的数据。正如Jared在评论中所述,JSON无法对函数进行字符串化,因此我创建了一个名为data
的对象,其中存储了模型的所有数据(例如 isLogged
变量)。
现在,每当我想要访问模型的数据时,首先获取其实例:let model = Model.getInstance();
,然后可以访问从init
函数中返回的方法。当我请求模型实例时,它首先检查当前实例是否尚未初始化。如果没有,它将调用load_localStorage
来读取localStorage并将其保存到data
变量中。
在重定向到另一个页面之前,我调用Model的实例的saveData
来将数据对象保存到localStorage中,以便重定向后的页面可以读取先前保存的状态。
在HTML文件中,我像这样包含了js文件:<script src="./../model/model.js"></script>
。
我确信有更好的解决方案来解决这个问题,也许有更可读的代码,但这对我来说完全可以正常工作
编辑:
需要注意的是,sessionStorage 可能比 localStorage 更好,因为localStorage不会过期,这意味着如果您保存的内容在服务器刷新/更新时需要刷新/清除,它仍然会从localStorage加载旧数据,因为没有发生变化。
例如,我在模型中保存了一些常见的HTML部分在localStorage中,每次运行 npm start
时它不会显示我对它所做的更改,因为我是从 localStorage
而不是从服务器再次加载HTML部分的。
英文:
Figured it out thanks to @Jared
I used localStorage to save the model's current state and load it back when redirecting to another page.
const Model = (function () {
let instance;
let data = {
isLogged: false,
};
function init_localStorage() {
save_localStorage();
}
function load_localStorage() {
let model = JSON.parse(localStorage.getItem('Model'));
if (Object.keys(model).length === 0) {
init_localStorage();
}
data = model;
}
function save_localStorage() {
localStorage.setItem('Model', JSON.stringify(data));
}
function init() {
load_localStorage();
return {
getIsLogged: function () {
return data.isLogged;
},
setIsLogged: function (l) {
data.isLogged = l;
},
saveData: function () {
save_localStorage();
}
}
}
return {
getInstance: function () {
if (! instance) {
instance = init();
}
return instance;
}
}
})();
Eventually, I have two main function: save...
and load...
which reads\saves from the localStorage object.
As Jared stated in the comments, JSON cannot stringify a function, thus I created an object called data
where I store all the model's data ( for example isLogged
variable ).
Now, whenever I want to access the model's data, I get its instance first: let model = Model.getInstance();
and then I can access the methods from the init
function that I'm returning.
When I request the Model instance, it first checks if the current instance is not yet initialized. If not, it calls the load_localStorage
which reads localStorage and saves it to data
variable.
Before I redirect to another page I call saveData
of Model's instance to save the data object to localStorage, so the page redirected to can read the previous saved state.
In HTML files, I included the js files like this: <script src="./../model/model.js"></script>
.
I'm sure there is a better solution to the problem, and maybe a more readable code, but this got me working just fine
Edit:
It is important to note that sessionStorage might be a better solution than localStorage as localStorage doesn't doesn't expire, meaning if you save things you want to be refreshed \ wiped out when the server is refreshed\updated, it will still load old data from localStorage as nothing changed.
For example, I saved some common HTML part in the model in localStorage, and each time I ran npm start
it didn't show the changes I made to it, as I'm loading the HTML part from localStorage
and not again from the server.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论