
本文介绍如何利用浏览器 web storage(localstorage/sessionstorage)配合立即执行函数表达式(iife)在纯静态 html 多页应用中实现真正持久化的单例模型,解决页面跳转后状态丢失的问题。
在基于 Express 的多页静态应用(MPA)中,每个 HTML 页面(如 /, /login)被独立响应(res.sendFile()),导致前端 JS 每次都重新加载、执行并初始化——这意味着传统内存级单例(如闭包私有变量)无法跨页面保留状态。用户登录后将 isLogged = true 写入内存,一旦跳转到新页面,model.js 重载,状态即刻清零。
根本解法不是阻止 JS 重载(这在 MPA 中不可行),而是将关键状态持久化到浏览器存储层,并在单例初始化时自动恢复。localStorage 和 sessionStorage 是标准、轻量且无需后端参与的理想选择:
- localStorage:数据永久保存(除非手动清除),适合长期状态(如用户偏好、主题设置);
- sessionStorage:数据仅限当前会话(关闭标签页即销毁),更契合登录态等需与浏览器会话生命周期对齐的场景,避免因缓存导致热更新失效(如修改了模板 HTML 却仍从旧 localStorage 加载)。
以下是一个健壮、可复用的单例模型实现(model.js):
const Model = (function () {
let instance;
// 状态容器:仅存放可序列化的纯数据(禁止函数、DOM 引用等)
const data = {
isLogged: false,
userId: null,
username: ''
};
// 从 storage 加载数据,失败则初始化默认值
function loadFromStorage() {
try {
const saved = localStorage.getItem('Model');
if (saved) {
Object.assign(data, JSON.parse(saved));
}
} catch (e) {
console.warn('Failed to load Model from localStorage:', e);
// 降级:使用默认值
Object.assign(data, { isLogged: false, userId: null, username: '' });
}
}
// 持久化当前 data 到 localStorage
function saveToStorage() {
try {
localStorage.setItem('Model', JSON.stringify(data));
} catch (e) {
console.error('Failed to save Model to localStorage:', e);
}
}
// 初始化单例实例(含状态恢复)
function init() {
loadFromStorage();
return {
getIsLogged: () => data.isLogged,
setIsLogged: (value) => { data.isLogged = Boolean(value); },
getUserId: () => data.userId,
setUserId: (id) => { data.userId = id; },
getUsername: () => data.username,
setUsername: (name) => { data.username = name; },
// 显式持久化调用(建议在关键操作后主动触发)
persist: saveToStorage,
// 可选:提供一键清除(如登出时)
clear: () => {
Object.keys(data).forEach(key => data[key] = undefined);
localStorage.removeItem('Model');
}
};
}
return {
getInstance: () => {
if (!instance) {
instance = init();
}
return instance;
}
};
})();✅ 使用方式(所有 HTML 页面中):
立即学习“Java免费学习笔记(深入)”;
⚠️ 重要注意事项:
- 仅存储可序列化数据:JSON.stringify() 会忽略函数、undefined、Symbol 和循环引用。务必确保 data 对象只含 string/number/boolean/null/object(扁平结构)和 array。
- sessionStorage 替换方案:若需会话级隔离,将上述代码中所有 localStorage 替换为 sessionStorage 即可,无需其他改动。
- 状态同步时机:getInstance() 自动加载,但写入必须显式调用 .persist() —— 这是明确的契约,避免意外覆盖或遗漏。
- 错误防御:已添加 try/catch 处理 localStorage 配额超限或禁用等边界情况,保障应用健壮性。
- 服务端热更新兼容性:使用 sessionStorage 可完全规避“HTML 模板更新后仍加载旧 localStorage 数据”的问题,推荐生产环境优先选用。
总结而言,在无前端构建工具、无路由库的纯 Vanilla MPA 场景下,结合 IIFE 封装 + Web Storage 持久化,是实现跨页面单例状态管理最简洁、可靠且符合 Web 标准的方案。它不依赖框架、不增加网络请求,同时兼顾开发体验与运行时稳定性。










