简介:本文深入解析IndexedDB作为前端本地存储数据库的核心机制,结合实际场景演示文件存储全流程,提供性能优化策略与错误处理方案,助力开发者构建高效可靠的离线文件管理系统。
现代Web应用对本地存储的需求催生了从Cookie到Web Storage再到IndexedDB的技术演进。Cookie受限于4KB容量和每次HTTP请求携带的缺陷,Web Storage(localStorage/sessionStorage)虽提供5MB容量,但仅支持键值对存储。IndexedDB作为浏览器内置的NoSQL数据库,突破性地支持结构化数据、事务处理和异步操作,成为大容量文件存储的首选方案。
IndexedDB特别适合存储用户上传的文档、图片、音频等二进制数据,典型应用包括:
// 打开或创建数据库const request = indexedDB.open('FileDB', 2);request.onupgradeneeded = (event) => {const db = event.target.result;// 创建对象仓库,autoIncrement设为true自动生成主键if (!db.objectStoreNames.contains('files')) {const store = db.createObjectStore('files', {keyPath: 'id',autoIncrement: true});// 创建索引支持按文件名查询store.createIndex('name', 'name', { unique: false });store.createIndex('type', 'type', { unique: false });}};
async function storeFile(file) {return new Promise((resolve, reject) => {const request = indexedDB.open('FileDB', 2);request.onsuccess = (event) => {const db = event.target.result;const tx = db.transaction('files', 'readwrite');const store = tx.objectStore('files');const fileData = {name: file.name,type: file.type,size: file.size,lastModified: file.lastModified,blob: file // 直接存储Blob对象};const addRequest = store.add(fileData);addRequest.onsuccess = () => resolve(addRequest.result);addRequest.onerror = (e) => reject(`存储失败: ${e.target.error}`);tx.oncomplete = () => db.close();};request.onerror = (e) => reject(`数据库打开失败: ${e.target.error}`);});}
async function getFile(id) {return new Promise((resolve, reject) => {const request = indexedDB.open('FileDB', 2);request.onsuccess = (event) => {const db = event.target.result;const tx = db.transaction('files', 'readonly');const store = tx.objectStore('files');const getRequest = store.get(id);getRequest.onsuccess = () => {const fileData = getRequest.result;if (fileData) {// 从Blob创建可下载的URLconst blob = new Blob([fileData.blob], { type: fileData.type });const url = URL.createObjectURL(blob);resolve({ url, fileData });} else {reject('文件不存在');}};getRequest.onerror = (e) => reject(`查询失败: ${e.target.error}`);tx.oncomplete = () => db.close();};});}
对于超过50MB的文件,建议采用分块存储策略:
async function storeLargeFile(file, chunkSize = 5 * 1024 * 1024) {const chunks = [];let offset = 0;while (offset < file.size) {const chunk = file.slice(offset, offset + chunkSize);const chunkData = {fileId: file.name, // 使用文件名作为关联标识chunkIndex: offset / chunkSize,blob: chunk,totalChunks: Math.ceil(file.size / chunkSize)};// 存储分块数据await storeChunk(chunkData);chunks.push(chunkData);offset += chunkSize;}return chunks;}
store.createIndex('name_type', ['name', 'type'], { unique: false });
// 获取存储使用情况navigator.storage.estimate().then(estimate => {console.log(`使用量: ${estimate.usage / (1024*1024)}MB`);console.log(`配额: ${estimate.quota / (1024*1024)}MB`);});// 清理过期文件async function cleanExpiredFiles(days = 30) {const cutoff = new Date();cutoff.setDate(cutoff.getDate() - days);// 实现基于最后访问时间的清理逻辑// ...}
function logIndexedDBError(event) {console.error(`IndexedDB错误: ${event.type}`, {error: event.target?.error,stack: new Error().stack});}
// 检测IndexedDB支持function isIndexedDBSupported() {return 'indexedDB' in window ||'webkitIndexedDB' in window ||'mozIndexedDB' in window ||'msIndexedDB' in window;}// 降级方案示例if (!isIndexedDBSupported()) {// 回退到File System Access API或临时文件方案}
数据模型设计:
事务管理:
安全实践:
性能监控:
迁移策略:
通过系统掌握IndexedDB的文件存储机制,开发者能够构建出具备离线能力、响应迅速的Web应用。实际开发中需结合具体业务场景,在存储效率、查询性能和用户体验之间取得平衡,同时做好异常处理和兼容性保障。