显示页面讨论过去修订反向链接回到顶部 本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。 ====== 第九部分:高级特性 ====== ===== 9.1 二进制数据存储 ===== ===== 9.1.1 Blob 和 File ===== IndexedDB 可以直接存储 Blob 和 File 对象: <code javascript> // 存储图片 async function storeImage(file) { const transaction = db.transaction(['images'], 'readwrite'); const store = transaction.objectStore('images'); const imageRecord = { id: generateId(), name: file.name, type: file.type, size: file.size, data: file, // 直接存储 File 对象 uploadedAt: new Date().toISOString() }; return new Promise((resolve, reject) => { const request = store.add(imageRecord); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } // 读取图片并显示 async function loadImage(id) { const transaction = db.transaction(['images'], 'readonly'); const store = transaction.objectStore('images'); const record = await new Promise((resolve, reject) => { const request = store.get(id); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); if (record) { const url = URL.createObjectURL(record.data); const img = document.createElement('img'); img.src = url; document.body.appendChild(img); } } </code> ===== 9.1.2 ArrayBuffer 和 TypedArray ===== <code javascript> // 存储二进制数据 async function storeBinaryData(id, arrayBuffer) { const transaction = db.transaction(['binaryData'], 'readwrite'); const store = transaction.objectStore('binaryData'); const record = { id, data: arrayBuffer, byteLength: arrayBuffer.byteLength, storedAt: new Date().toISOString() }; await store.put(record); } // 存储 TypedArray async functionStoreTypedArray(id, floatArray) { const transaction = db.transaction(['numbers'], 'readwrite'); const store = transaction.objectStore('numbers'); await store.put({ id, data: floatArray, // Float32Array 等 type: floatArray.constructor.name }); } </code> ===== 9.2 在 Web Worker 中使用 ===== ===== 9.2.1 Worker 中的数据库操作 ===== <code javascript> // worker.js let db = null; self.onmessage = function(event) { const { action, data } = event.data; switch (action) { case 'open': openDatabase(data.dbName, data.version); break; case 'add': addData(data.storeName, data.record); break; case 'get': getData(data.storeName, data.key); break; case 'query': queryData(data.storeName, data.index, data.range); break; } }; function openDatabase(dbName, version) { const request = indexedDB.open(dbName, version); request.onupgradeneeded = function(event) { const db = event.target.result; if (!db.objectStoreNames.contains('data')) { db.createObjectStore('data', { keyPath: 'id' }); } }; request.onsuccess = function(event) { db = event.target.result; self.postMessage({ type: 'ready' }); }; request.onerror = function(event) { self.postMessage({ type: 'error', error: event.target.error.message }); }; } function addData(storeName, record) { const transaction = db.transaction([storeName], 'readwrite'); const store = transaction.objectStore(storeName); const request = store.add(record); request.onsuccess = () => { self.postMessage({ type: 'added', key: request.result }); }; } function getData(storeName, key) { const transaction = db.transaction([storeName], 'readonly'); const store = transaction.objectStore(storeName); const request = store.get(key); request.onsuccess = () => { self.postMessage({ type: 'result', data: request.result }); }; } // main.js const worker = new Worker('worker.js'); worker.postMessage({ action: 'open', data: { dbName: 'WorkerDB', version: 1 } }); worker.onmessage = function(event) { if (event.data.type === 'ready') { console.log('Worker 数据库就绪'); // 发送数据 worker.postMessage({ action: 'add', data: { storeName: 'data', record: { id: 1, value: '测试数据' } } }); } if (event.data.type === 'added') { console.log('数据已添加:', event.data.key); } }; </code> ===== 9.3 大数据集处理 ===== ===== 9.3.1 流式处理 ===== <code javascript> // 处理大量数据,避免内存溢出 async function* streamRecords(storeName, batchSize = 100) { const transaction = db.transaction([storeName], 'readonly'); const store = transaction.objectStore(storeName); let batch = []; await new Promise((resolve, reject) => { const request = store.openCursor(); request.onsuccess = (event) => { const cursor = event.target.result; if (cursor) { batch.push(cursor.value); if (batch.length >= batchSize) { resolve(); } else { cursor.continue(); } } else { resolve(); } }; request.onerror = () => reject(request.error); }); if (batch.length > 0) { yield batch; } } // 使用 for await (const batch of streamRecords('logs', 500)) { console.log('处理批次:', batch.length); await processBatch(batch); } </code> ===== 9.3.2 数据导入导出 ===== <code javascript> // 导出为 JSON async function exportToJSON(storeName) { const transaction = db.transaction([storeName], 'readonly'); const store = transaction.objectStore(storeName); const records = await store.getAll(); // 处理不可序列化的数据 const serialized = records.map(record => { const copy = { ...record }; // 将 Blob 转为 base64 或标记 if (copy.data instanceof Blob) { copy._hasBlob = true; copy._blobType = copy.data.type; delete copy.data; // 不导出二进制数据 } return copy; }); return JSON.stringify(serialized, null, 2); } // 从 JSON 导入 async function importFromJSON(storeName, jsonString) { const records = JSON.parse(jsonString); const transaction = db.transaction([storeName], 'readwrite'); const store = transaction.objectStore(storeName); for (const record of records) { await store.put(record); } } </code> ===== 9.4 复合索引高级用法 ===== ===== 9.4.1 多字段查询 ===== <code javascript> // 创建复合索引 const store = db.createObjectStore('products', { keyPath: 'sku' }); store.createIndex('categoryPriceIndex', ['category', 'price']); store.createIndex('brandRatingIndex', ['brand', 'rating'], { unique: false }); // 查询特定分类中价格范围内的产品 function findProducts(category, minPrice, maxPrice) { const transaction = db.transaction(['products'], 'readonly'); const store = transaction.objectStore('products'); const index = store.index('categoryPriceIndex'); // 复合索引的范围查询 const range = IDBKeyRange.bound( [category, minPrice], [category, maxPrice] ); return index.getAll(range); } // 查询特定品牌的所有产品(忽略第二个字段) function findByBrand(brand) { const transaction = db.transaction(['products'], 'readonly'); const store = transaction.objectStore('products'); const index = store.index('brandRatingIndex'); // 只指定第一个字段,第二个字段用范围 const range = IDBKeyRange.bound( [brand, -Infinity], [brand, Infinity] ); return index.getAll(range); } </code> ===== 9.5 存储持久化 ===== ===== 9.5.1 请求持久存储 ===== <code javascript> async function requestPersistentStorage() { if (navigator.storage && navigator.storage.persist) { const isPersistent = await navigator.storage.persist(); if (isPersistent) { console.log('已获取持久存储权限'); } else { console.log('持久存储请求被拒绝'); } return isPersistent; } return false; } // 检查存储持久化状态 async function checkPersistence() { if (navigator.storage && navigator.storage.persisted) { const persisted = await navigator.storage.persisted(); console.log('存储是否持久化:', persisted); return persisted; } return false; } </code> ===== 9.6 本章小结 ===== 本章介绍了 IndexedDB 的高级特性: * 支持 Blob、File、ArrayBuffer 等二进制数据 * 可以在 Web Worker 中异步处理数据 * 流式处理大数据集避免内存问题 * 复合索引支持多字段查询 * 可请求持久存储防止数据被清理 继续阅读 [[part10-performance|第十部分:性能优化]]。 登录 Detach Close 该主题尚不存在 您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。 indexeddb/part09-advanced.txt 最后更改: 2026/04/27 19:53由 张叶安 登录