javascript中用indexeddb缓存在线考试答题卡的核心是:创建examdb数据库和answersheets对象存储,以studentid为主键、examid为索引,实现增删查改;页面加载时优先读取缓存,卸载前自动保存,提交后及时清理。

在 JavaScript 中用 IndexedDB 缓存在线考试答题卡的临时数据,核心是:创建数据库、设计对象存储、增删查改答题记录,并在页面卸载前自动保存,在加载时优先读取缓存。关键在于结构清晰、操作可靠、避免阻塞主线程。
1. 初始化考试专用数据库和答题卡对象存储
首次打开考试页时,打开或创建名为 examDB 的数据库,版本设为 1;定义一个叫 answerSheets 的对象存储空间,以考生 ID(如 studentId)为主键,支持按考试 ID(examId)查询:
const DB_NAME = 'examDB';
const STORE_NAME = 'answerSheets';
let db;
function initDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, 1);
request.onupgradeneeded = (event) => {
db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
// 主键为 studentId,启用 autoIncrement 仅用于兜底(实际不用)
const store = db.createObjectStore(STORE_NAME, { keyPath: 'studentId' });
// 创建二级索引,方便按 examId 查所有该考试的答题卡
store.createIndex('byExamId', 'examId', { unique: false });
}
};
request.onsuccess = () => {
db = request.result;
resolve(db);
};
request.onerror = () => reject(request.error);
});
}
2. 保存/更新当前答题卡(自动覆盖同用户同考试)
每次用户切换题、点击选项、输入文字后,调用保存逻辑。使用 put() 自动插入或更新——只要 studentId 和 examId 相同,就覆盖旧数据:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
async function saveAnswerSheet(sheet) {
if (!db) await initDB();
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE_NAME, 'readwrite');
const store = tx.objectStore(STORE_NAME);
const request = store.put(sheet); // sheet 必须含 studentId 字段
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
// 示例调用:
saveAnswerSheet({
studentId: 'S1001',
examId: 'EXAM20240501',
answers: { q1: 'A', q2: 'true', q3: '手动输入内容...' },
timestamp: Date.now()
});
3. 加载缓存答题卡(页面初始化时优先读取)
进入考试页时,立即尝试从 IndexedDB 加载对应用户的最新答题卡。推荐用索引查 examId + studentId 组合,确保精准:
async function loadAnswerSheet(studentId, examId) {
if (!db) await initDB();
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE_NAME, 'readonly');
const store = tx.objectStore(STORE_NAME);
const index = store.index('byExamId');
// 先按 examId 查出所有匹配项,再过滤 studentId(因索引不唯一)
const request = index.getAll(IDBKeyRange.only(examId));
request.onsuccess = () => {
const sheets = request.result.filter(s => s.studentId === studentId);
resolve(sheets.length ? sheets[0] : null);
};
request.onerror = () => reject(request.error);
});
}
// 页面加载后调用:
loadAnswerSheet('S1001', 'EXAM20240501').then(sheet => {
if (sheet) {
restoreUI(sheet.answers); // 把 answers 数据还原到题目组件
}
});
4. 安全清理与生命周期配合
答题提交成功后,应主动删除缓存;用户退出考试页(非刷新)时也建议清除,避免残留。同时监听 beforeunload 做最后保存(但注意:该事件中不能用 async/await,需同步写):
- 提交后调用
deleteAnswerSheet(studentId, examId)(用delete()方法) - 页面卸载前触发一次同步保存:
window.addEventListener('beforeunload', () => saveAnswerSheetSync(...))(封装成不返回 Promise 的同步版本) - 考试超时或主动交卷时,清空当前考试的所有缓存(可扩展支持多场考试并行)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










