现代Web存储技术(六):企业级性能优化与监控体系
【摘要】 深入探讨Web存储的性能优化技巧,提供实用的最佳实践和常见问题解决方案,帮助开发者构建高性能的Web应用。用户在地铁里刷新闻,每次加载都要等3秒;在线文档编辑器,每次保存都卡顿1秒;音乐播放器切换歌曲时出现明显延迟;游戏存档读取时间过长,影响游戏体验。这些问题的根源往往在于存储性能。一个高性能的存储系统不仅能提升用户体验,还能减少服务器压力,降低运营成本。 1. 性能基准测试与监控 1.1 ...
深入探讨Web存储的性能优化技巧,提供实用的最佳实践和常见问题解决方案,帮助开发者构建高性能的Web应用。
用户在地铁里刷新闻,每次加载都要等3秒;在线文档编辑器,每次保存都卡顿1秒;音乐播放器切换歌曲时出现明显延迟;游戏存档读取时间过长,影响游戏体验。
这些问题的根源往往在于存储性能。一个高性能的存储系统不仅能提升用户体验,还能减少服务器压力,降低运营成本。
1. 性能基准测试与监控
1.1 建立性能基准
在优化之前,我们需要知道当前的性能水平:
class StoragePerformanceBenchmark {
constructor() {
this.results = {};
this.testData = this.generateTestData();
}
// 生成测试数据
generateTestData() {
const sizes = {
small: this.createTestObject(1024), // 1KB
medium: this.createTestObject(100 * 1024), // 100KB
large: this.createTestObject(1024 * 1024), // 1MB
huge: this.createTestObject(10 * 1024 * 1024) // 10MB
};
return sizes;
}
createTestObject(targetSize) {
const baseObj = {
id: Math.random().toString(36),
timestamp: Date.now(),
type: 'test-data'
};
// 填充到目标大小
const currentSize = JSON.stringify(baseObj).length;
const remainingSize = targetSize - currentSize;
if (remainingSize > 0) {
baseObj.padding = 'x'.repeat(remainingSize);
}
return baseObj;
}
// 运行完整基准测试
async runFullBenchmark() {
console.log('开始存储性能基准测试...');
// 测试各种存储方案
await this.benchmarkLocalStorage();
await this.benchmarkSessionStorage();
await this.benchmarkIndexedDB();
await this.benchmarkCacheAPI();
await this.benchmarkOPFS();
// 生成报告
this.generateReport();
return this.results;
}
// LocalStorage基准测试
async benchmarkLocalStorage() {
console.log('测试LocalStorage性能...');
const results = {
write: {},
read: {},
errors: []
};
for (const [size, data] of Object.entries(this.testData)) {
try {
// 写入测试
const writeStart = performance.now();
localStorage.setItem(`test-${size}`, JSON.stringify(data));
const writeEnd = performance.now();
results.write[size] = writeEnd - writeStart;
// 读取测试
const readStart = performance.now();
const retrieved = JSON.parse(localStorage.getItem(`test-${size}`));
const readEnd = performance.now();
results.read[size] = readEnd - readStart;
// 清理
localStorage.removeItem(`test-${size}`);
} catch (error) {
results.errors.push({ size, error: error.message });
}
}
this.results.localStorage = results;
}
// IndexedDB基准测试
async benchmarkIndexedDB() {
console.log('测试IndexedDB性能...');
const results = {
write: {},
read: {},
batchWrite: {},
query: {},
errors: []
};
try {
const db = await this.openTestDB();
for (const [size, data] of Object.entries(this.testData)) {
try {
// 单条写入测试
const writeStart = performance.now();
await this.writeToIndexedDB(db, `test-${size}`, data);
const writeEnd = performance.now();
results.write[size] = writeEnd - writeStart;
// 读取测试
const readStart = performance.now();
const retrieved = await this.readFromIndexedDB(db, `test-${size}`);
const readEnd = performance.now();
results.read[size] = readEnd - readStart;
// 批量写入测试(100条记录)
const batchData = Array(100).fill(data).map((item, index) => ({
...item,
id: `batch-${size}-${index}`
}));
const batchStart = performance.now();
await this.batchWriteToIndexedDB(db, batchData);
const batchEnd = performance.now();
results.batchWrite[size] = batchEnd - batchStart;
// 查询测试
const queryStart = performance.now();
const queryResults = await this.queryIndexedDB(db, 'type', 'test-data');
const queryEnd = performance.now();
results.query[size] = queryEnd - queryStart;
} catch (error) {
results.errors.push({ size, error: error.message });
}
}
db.close();
} catch (error) {
results.errors.push({ operation: 'db-open', error: error.message });
}
this.results.indexedDB = results;
}
// Cache API基准测试
async benchmarkCacheAPI() {
console.log('测试Cache API性能...');
const results = {
write: {},
read: {},
errors: []
};
try {
const cache = await caches.open('performance-test');
for (const [size, data] of Object.entries(this.testData)) {
try {
const url = `/test-${size}`;
const response = new Response(JSON.stringify(data));
// 写入测试
const writeStart = performance.now();
await cache.put(url, response.clone());
const writeEnd = performance.now();
results.write[size] = writeEnd - writeStart;
// 读取测试
const readStart = performance.now();
const cachedResponse = await cache.match(url);
const retrieved = await cachedResponse.json();
const readEnd = performance.now();
results.read[size] = readEnd - readStart;
} catch (error) {
results.errors.push({ size, error: error.message });
}
}
// 清理
await caches.delete('performance-test');
} catch (error) {
results.errors.push({ operation: 'cache-open', error: error.message });
}
this.results.cacheAPI = results;
}
// OPFS基准测试
async benchmarkOPFS() {
console.log('测试OPFS性能...');
const results = {
write: {},
read: {},
stream: {},
errors: []
};
if (!('storage' in navigator) || !('getDirectory' in navigator.storage)) {
results.errors.push({ error: 'OPFS not supported' });
this.results.opfs = results;
return;
}
try {
const opfsRoot = await navigator.storage.getDirectory();
for (const [size, data] of Object.entries(this.testData)) {
try {
const filename = `test-${size}.json`;
const jsonData = JSON.stringify(data);
// 写入测试
const writeStart = performance.now();
const fileHandle = await opfsRoot.getFileHandle(filename, { create: true });
const writable = await fileHandle.createWritable();
await writable.write(jsonData);
await writable.close();
const writeEnd = performance.now();
results.write[size] = writeEnd - writeStart;
// 读取测试
const readStart = performance.now();
const file = await fileHandle.getFile();
const content = await file.text();
const retrieved = JSON.parse(content);
const readEnd = performance.now();
results.read[size] = readEnd - readStart;
// 流式写入测试(大文件)
if (size === 'huge') {
const streamStart = performance.now();
const streamWritable = await fileHandle.createWritable();
// 分块写入
const chunkSize = 64 * 1024; // 64KB chunks
for (let i = 0; i < jsonData.length; i += chunkSize) {
const chunk = jsonData.slice(i, i + chunkSize);
await streamWritable.write(chunk);
}
await streamWritable.close();
const streamEnd = performance.now();
results.stream[size] = streamEnd - streamStart;
}
// 清理
await opfsRoot.removeEntry(filename);
} catch (error) {
results.errors.push({ size, error: error.message });
}
}
} catch (error) {
results.errors.push({ operation: 'opfs-init', error: error.message });
}
this.results.opfs = results;
}
// 生成性能报告
generateReport() {
console.log('\n存储性能基准测试报告');
console.log('=' .repeat(50));
const storageTypes = Object.keys(this.results);
const dataSizes = ['small', 'medium', 'large', 'huge'];
// 写入性能对比
console.log('\n写入性能 (毫秒)');
console.log('-'.repeat(30));
const writeTable = {};
storageTypes.forEach(type => {
writeTable[type] = {};
dataSizes.forEach(size => {
const result = this.results[type];
if (result && result.write && result.write[size] !== undefined) {
writeTable[type][size] = result.write[size].toFixed(2);
} else {
writeTable[type][size] = 'N/A';
}
});
});
console.table(writeTable);
// 读取性能对比
console.log('\n读取性能 (毫秒)');
console.log('-'.repeat(30));
const readTable = {};
storageTypes.forEach(type => {
readTable[type] = {};
dataSizes.forEach(size => {
const result = this.results[type];
if (result && result.read && result.read[size] !== undefined) {
readTable[type][size] = result.read[size].toFixed(2);
} else {
readTable[type][size] = 'N/A';
}
});
});
console.table(readTable);
// 性能建议
this.generateRecommendations();
}
// 生成性能建议
generateRecommendations() {
console.log('\n性能优化建议');
console.log('-'.repeat(30));
const recommendations = [];
// 分析写入性能
const writePerf = this.analyzeWritePerformance();
if (writePerf.slowest) {
recommendations.push(`${writePerf.slowest} 写入性能较慢,考虑使用批量操作`);
}
// 分析读取性能
const readPerf = this.analyzeReadPerformance();
if (readPerf.fastest) {
recommendations.push(`${readPerf.fastest} 读取性能最佳,适合频繁访问的数据`);
}
// 分析大文件处理
const largeFilePerf = this.analyzeLargeFilePerformance();
if (largeFilePerf.recommendation) {
recommendations.push(largeFilePerf.recommendation);
}
recommendations.forEach(rec => console.log(rec));
}
// 分析写入性能
analyzeWritePerformance() {
const writePerfs = {};
Object.keys(this.results).forEach(type => {
const result = this.results[type];
if (result.write && result.write.medium) {
writePerfs[type] = result.write.medium;
}
});
const slowest = Object.keys(writePerfs).reduce((a, b) =>
writePerfs[a] > writePerfs[b] ? a : b
);
return { slowest, perfs: writePerfs };
}
// 分析读取性能
analyzeReadPerformance() {
const readPerfs = {};
Object.keys(this.results).forEach(type => {
const result = this.results[type];
if (result.read && result.read.medium) {
readPerfs[type] = result.read.medium;
}
});
const fastest = Object.keys(readPerfs).reduce((a, b) =>
readPerfs[a] < readPerfs[b] ? a : b
);
return { fastest, perfs: readPerfs };
}
// 分析大文件性能
analyzeLargeFilePerformance() {
const opfsResult = this.results.opfs;
if (opfsResult && opfsResult.write && opfsResult.write.huge > 1000) {
return {
recommendation: '大文件建议使用OPFS流式写入,可以提升性能'
};
}
return {};
}
// 辅助方法
async openTestDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('performance-test', 1);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains('test')) {
const store = db.createObjectStore('test', { keyPath: 'id' });
store.createIndex('type', 'type', { unique: false });
}
};
});
}
async writeToIndexedDB(db, key, data) {
const transaction = db.transaction(['test'], 'readwrite');
const store = transaction.objectStore('test');
return new Promise((resolve, reject) => {
const request = store.put({ id: key, ...data });
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
async readFromIndexedDB(db, key) {
const transaction = db.transaction(['test'], 'readonly');
const store = transaction.objectStore('test');
return new Promise((resolve, reject) => {
const request = store.get(key);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async batchWriteToIndexedDB(db, dataArray) {
const transaction = db.transaction(['test'], 'readwrite');
const store = transaction.objectStore('test');
const promises = dataArray.map(data => {
return new Promise((resolve, reject) => {
const request = store.put(data);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
});
return Promise.all(promises);
}
async queryIndexedDB(db, indexName, value) {
const transaction = db.transaction(['test'], 'readonly');
const store = transaction.objectStore('test');
const index = store.index(indexName);
return new Promise((resolve, reject) => {
const request = index.getAll(value);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
}
// 使用示例
const benchmark = new StoragePerformanceBenchmark();
// 运行基准测试
benchmark.runFullBenchmark().then(results => {
console.log('基准测试完成,结果已保存');
// 可以将结果保存到本地
localStorage.setItem('storage-benchmark', JSON.stringify(results));
});
1.2 实时性能监控
class StoragePerformanceMonitor {
constructor() {
this.metrics = {
operations: [],
errors: [],
slowQueries: []
};
this.thresholds = {
slowOperation: 100, // 100ms
errorRate: 0.05, // 5%
memoryUsage: 0.8 // 80%
};
this.init();
}
init() {
// 监控存储操作
this.wrapStorageAPIs();
// 定期生成报告
setInterval(() => {
this.generatePerformanceReport();
}, 60000); // 每分钟
// 监控内存使用
this.monitorMemoryUsage();
}
// 包装存储API以监控性能
wrapStorageAPIs() {
// 包装IndexedDB
this.wrapIndexedDB();
// 包装Cache API
this.wrapCacheAPI();
// 包装LocalStorage
this.wrapLocalStorage();
}
// 包装IndexedDB操作
wrapIndexedDB() {
const originalOpen = indexedDB.open;
const monitor = this;
indexedDB.open = function(...args) {
const startTime = performance.now();
const request = originalOpen.apply(this, args);
request.onsuccess = function(event) {
const endTime = performance.now();
monitor.recordOperation('indexeddb', 'open', endTime - startTime, true);
// 包装数据库操作
const db = event.target.result;
monitor.wrapDatabaseOperations(db);
};
request.onerror = function(event) {
const endTime = performance.now();
monitor.recordOperation('indexeddb', 'open', endTime - startTime, false, event.target.error);
};
return request;
};
}
// 包装数据库操作
wrapDatabaseOperations(db) {
const monitor = this;
const originalTransaction = db.transaction;
db.transaction = function(...args) {
const transaction = originalTransaction.apply(this, args);
const startTime = performance.now();
transaction.oncomplete = function() {
const endTime = performance.now();
monitor.recordOperation('indexeddb', 'transaction', endTime - startTime, true);
};
transaction.onerror = function(event) {
const endTime = performance.now();
monitor.recordOperation('indexeddb', 'transaction', endTime - startTime, false, event.target.error);
};
return transaction;
};
}
// 记录操作指标
recordOperation(storageType, operation, duration, success, error = null) {
const record = {
timestamp: Date.now(),
storageType,
operation,
duration,
success,
error: error ? error.message : null
};
this.metrics.operations.push(record);
// 检查是否为慢操作
if (duration > this.thresholds.slowOperation) {
this.metrics.slowQueries.push(record);
console.warn(`慢操作检测: ${storageType}.${operation} 耗时 ${duration.toFixed(2)}ms`);
}
// 记录错误
if (!success) {
this.metrics.errors.push(record);
console.error(`存储操作失败: ${storageType}.${operation}`, error);
}
// 限制记录数量
this.limitMetricsSize();
}
// 限制指标记录数量
limitMetricsSize() {
const maxRecords = 1000;
if (this.metrics.operations.length > maxRecords) {
this.metrics.operations = this.metrics.operations.slice(-maxRecords);
}
if (this.metrics.slowQueries.length > 100) {
this.metrics.slowQueries = this.metrics.slowQueries.slice(-100);
}
if (this.metrics.errors.length > 100) {
this.metrics.errors = this.metrics.errors.slice(-100);
}
}
// 生成性能报告
generatePerformanceReport() {
const now = Date.now();
const oneMinuteAgo = now - 60000;
// 过滤最近一分钟的数据
const recentOps = this.metrics.operations.filter(op => op.timestamp > oneMinuteAgo);
const recentErrors = this.metrics.errors.filter(err => err.timestamp > oneMinuteAgo);
const recentSlowOps = this.metrics.slowQueries.filter(op => op.timestamp > oneMinuteAgo);
if (recentOps.length === 0) return;
// 计算统计数据
const stats = this.calculateStats(recentOps);
const errorRate = recentErrors.length / recentOps.length;
console.log('\n存储性能报告 (最近1分钟)');
console.log('-'.repeat(40));
console.log(`总操作数: ${recentOps.length}`);
console.log(`平均响应时间: ${stats.avgDuration.toFixed(2)}ms`);
console.log(`最大响应时间: ${stats.maxDuration.toFixed(2)}ms`);
console.log(`错误率: ${(errorRate * 100).toFixed(2)}%`);
console.log(`慢操作数: ${recentSlowOps.length}`);
// 按存储类型分组统计
const byType = this.groupByStorageType(recentOps);
console.log('\n按存储类型统计:');
Object.keys(byType).forEach(type => {
const typeStats = this.calculateStats(byType[type]);
console.log(` ${type}: ${byType[type].length}次操作, 平均${typeStats.avgDuration.toFixed(2)}ms`);
});
// 性能警告
this.checkPerformanceAlerts(stats, errorRate, recentSlowOps.length);
}
// 计算统计数据
calculateStats(operations) {
if (operations.length === 0) {
return { avgDuration: 0, maxDuration: 0, minDuration: 0 };
}
const durations = operations.map(op => op.duration);
return {
avgDuration: durations.reduce((sum, d) => sum + d, 0) / durations.length,
maxDuration: Math.max(...durations),
minDuration: Math.min(...durations)
};
}
// 按存储类型分组
groupByStorageType(operations) {
return operations.reduce((groups, op) => {
if (!groups[op.storageType]) {
groups[op.storageType] = [];
}
groups[op.storageType].push(op);
return groups;
}, {});
}
// 检查性能警告
checkPerformanceAlerts(stats, errorRate, slowOpCount) {
if (stats.avgDuration > this.thresholds.slowOperation) {
console.warn('警告: 平均响应时间过高');
}
if (errorRate > this.thresholds.errorRate) {
console.warn('警告: 错误率过高');
}
if (slowOpCount > 10) {
console.warn('警告: 慢操作过多');
}
}
// 监控内存使用
async monitorMemoryUsage() {
if ('memory' in performance) {
setInterval(() => {
const memInfo = performance.memory;
const usageRatio = memInfo.usedJSHeapSize / memInfo.jsHeapSizeLimit;
if (usageRatio > this.thresholds.memoryUsage) {
console.warn(`内存使用率过高: ${(usageRatio * 100).toFixed(2)}%`);
}
}, 30000); // 每30秒检查一次
}
}
}
// 使用示例
const monitor = new StoragePerformanceMonitor();
// 监听性能警告
window.addEventListener('storage-performance-warning', (event) => {
console.warn('存储性能警告:', event.detail);
});
2. 批量操作优化
2.1 IndexedDB批量操作
单条操作vs批量操作的性能差异巨大:
class BatchOperationManager {
constructor() {
this.batchSize = 100;
this.pendingOperations = [];
this.batchTimer = null;
this.batchDelay = 50; // 50ms延迟批处理
}
// 批量写入优化
async batchWrite(storeName, dataArray, options = {}) {
const {
batchSize = this.batchSize,
onProgress = null,
onError = null
} = options;
const db = await this.openDB();
const results = [];
const errors = [];
// 分批处理
for (let i = 0; i < dataArray.length; i += batchSize) {
const batch = dataArray.slice(i, i + batchSize);
try {
const batchResult = await this.processBatch(db, storeName, batch);
results.push(...batchResult);
// 进度回调
if (onProgress) {
onProgress({
processed: Math.min(i + batchSize, dataArray.length),
total: dataArray.length,
percentage: Math.min((i + batchSize) / dataArray.length * 100, 100)
});
}
} catch (error) {
errors.push({ batch: i / batchSize, error });
if (onError) {
onError(error, batch);
}
}
}
db.close();
return {
success: results.length,
errors: errors.length,
results,
errorDetails: errors
};
}
// 处理单个批次
async processBatch(db, storeName, batch) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], 'readwrite');
const store = transaction.objectStore('test');
const results = [];
transaction.oncomplete = () => resolve(results);
transaction.onerror = () => reject(transaction.error);
// 批量添加数据
batch.forEach((item, index) => {
const request = store.put(item);
request.onsuccess = () => {
results.push({ index, success: true, key: request.result });
};
request.onerror = () => {
results.push({ index, success: false, error: request.error });
};
});
});
}
// 智能批处理队列
queueOperation(operation) {
this.pendingOperations.push(operation);
// 清除之前的定时器
if (this.batchTimer) {
clearTimeout(this.batchTimer);
}
// 设置新的批处理定时器
this.batchTimer = setTimeout(() => {
this.processPendingOperations();
}, this.batchDelay);
// 如果队列满了,立即处理
if (this.pendingOperations.length >= this.batchSize) {
clearTimeout(this.batchTimer);
this.processPendingOperations();
}
}
// 处理待处理操作
async processPendingOperations() {
if (this.pendingOperations.length === 0) return;
const operations = [...this.pendingOperations];
this.pendingOperations = [];
// 按操作类型分组
const groupedOps = this.groupOperationsByType(operations);
// 并行处理不同类型的操作
const promises = Object.keys(groupedOps).map(type => {
return this.processOperationGroup(type, groupedOps[type]);
});
try {
await Promise.all(promises);
console.log(`批处理完成: ${operations.length} 个操作`);
} catch (error) {
console.error('批处理失败:', error);
}
}
// 按操作类型分组
groupOperationsByType(operations) {
return operations.reduce((groups, op) => {
const key = `${op.storeName}-${op.type}`;
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(op);
return groups;
}, {});
}
// 处理操作组
async processOperationGroup(groupKey, operations) {
const [storeName, operationType] = groupKey.split('-');
switch (operationType) {
case 'write':
return this.batchWrite(storeName, operations.map(op => op.data));
case 'delete':
return this.batchDelete(storeName, operations.map(op => op.key));
case 'update':
return this.batchUpdate(storeName, operations);
default:
console.warn(`未知操作类型: ${operationType}`);
}
}
// 批量删除
async batchDelete(storeName, keys) {
const db = await this.openDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], 'readwrite');
const store = transaction.objectStore('test');
const results = [];
transaction.oncomplete = () => {
db.close();
resolve(results);
};
transaction.onerror = () => {
db.close();
reject(transaction.error);
};
keys.forEach((key, index) => {
const request = store.delete(key);
request.onsuccess = () => {
results.push({ index, key, success: true });
};
request.onerror = () => {
results.push({ index, key, success: false, error: request.error });
};
});
});
}
// 批量更新
async batchUpdate(storeName, operations) {
const db = await this.openDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], 'readwrite');
const store = transaction.objectStore('test');
const results = [];
transaction.oncomplete = () => {
db.close();
resolve(results);
};
transaction.onerror = () => {
db.close();
reject(transaction.error);
};
operations.forEach((op, index) => {
// 先读取现有数据
const getRequest = store.get(op.key);
getRequest.onsuccess = () => {
const existingData = getRequest.result;
if (existingData) {
// 合并数据
const updatedData = { ...existingData, ...op.updates };
// 写回数据库
const putRequest = store.put(updatedData);
putRequest.onsuccess = () => {
results.push({ index, key: op.key, success: true });
};
putRequest.onerror = () => {
results.push({ index, key: op.key, success: false, error: putRequest.error });
};
} else {
results.push({ index, key: op.key, success: false, error: 'Record not found' });
}
};
getRequest.onerror = () => {
results.push({ index, key: op.key, success: false, error: getRequest.error });
};
});
});
}
// 打开数据库
async openDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('batch-operations', 1);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains('test')) {
const store = db.createObjectStore('test', { keyPath: 'id' });
store.createIndex('category', 'category', { unique: false });
store.createIndex('timestamp', 'timestamp', { unique: false });
}
};
});
}
}
// 使用示例
const batchManager = new BatchOperationManager();
// 批量写入大量数据
const largeDataset = Array(10000).fill(null).map((_, index) => ({
id: `item-${index}`,
name: `Item ${index}`,
category: `category-${index % 10}`,
timestamp: Date.now() + index,
data: `Some data for item ${index}`
}));
// 带进度回调的批量写入
batchManager.batchWrite('test', largeDataset, {
batchSize: 200,
onProgress: (progress) => {
console.log(`进度: ${progress.percentage.toFixed(2)}% (${progress.processed}/${progress.total})`);
},
onError: (error, batch) => {
console.error('批次处理失败:', error);
}
}).then(result => {
console.log('批量写入完成:', result);
});
// 使用智能队列
for (let i = 0; i < 1000; i++) {
batchManager.queueOperation({
type: 'write',
storeName: 'test',
data: {
id: `queued-${i}`,
value: Math.random()
}
});
}
2.2 Cache API批量操作
class CacheBatchManager {
constructor() {
this.batchSize = 50;
this.concurrentLimit = 5;
}
// 批量缓存资源
async batchCacheResources(cacheName, resources, options = {}) {
const {
batchSize = this.batchSize,
concurrentLimit = this.concurrentLimit,
onProgress = null
} = options;
const cache = await caches.open(cacheName);
const results = [];
const errors = [];
// 分批处理
for (let i = 0; i < resources.length; i += batchSize) {
const batch = resources.slice(i, i + batchSize);
try {
// 限制并发数
const chunks = this.chunkArray(batch, concurrentLimit);
for (const chunk of chunks) {
const chunkPromises = chunk.map(resource =>
this.cacheResource(cache, resource)
);
const chunkResults = await Promise.allSettled(chunkPromises);
chunkResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
results.push(result.value);
} else {
errors.push({
resource: chunk[index],
error: result.reason
});
}
});
}
// 进度回调
if (onProgress) {
onProgress({
processed: Math.min(i + batchSize, resources.length),
total: resources.length,
percentage: Math.min((i + batchSize) / resources.length * 100, 100)
});
}
} catch (error) {
console.error('批次缓存失败:', error);
}
}
return {
success: results.length,
errors: errors.length,
results,
errorDetails: errors
};
}
// 缓存单个资源
async cacheResource(cache, resource) {
const { url, options = {} } = resource;
try {
// 检查是否已缓存
const existing = await cache.match(url);
if (existing && !options.force) {
return { url, status: 'already-cached' };
}
// 获取资源
const response = await fetch(url, options.fetchOptions);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
// 缓存资源
await cache.put(url, response.clone());
return {
url,
status: 'cached',
size: response.headers.get('content-length') || 'unknown'
};
} catch (error) {
throw new Error(`缓存失败 ${url}: ${error.message}`);
}
}
// 预加载关键资源
async preloadCriticalResources(resources) {
console.log('开始预加载关键资源...');
const criticalCache = await caches.open('critical-resources');
const results = [];
// 并行预加载
const promises = resources.map(async (resource) => {
try {
const startTime = performance.now();
// 使用高优先级获取
const response = await fetch(resource.url, {
priority: 'high',
...resource.options
});
if (response.ok) {
await criticalCache.put(resource.url, response.clone());
const endTime = performance.now();
results.push({
url: resource.url,
success: true,
loadTime: endTime - startTime,
size: response.headers.get('content-length')
});
}
} catch (error) {
results.push({
url: resource.url,
success: false,
error: error.message
});
}
});
await Promise.all(promises);
console.log('关键资源预加载完成:', results);
return results;
}
// 智能缓存更新
async smartCacheUpdate(cacheName, resources) {
const cache = await caches.open(cacheName);
const updates = [];
// 检查哪些资源需要更新
for (const resource of resources) {
const cached = await cache.match(resource.url);
if (!cached) {
updates.push({ ...resource, action: 'add' });
continue;
}
// 检查是否需要更新
const needsUpdate = await this.checkIfNeedsUpdate(cached, resource);
if (needsUpdate) {
updates.push({ ...resource, action: 'update' });
}
}
if (updates.length === 0) {
console.log('所有资源都是最新的');
return { updated: 0, added: 0 };
}
// 批量更新
const result = await this.batchCacheResources(cacheName, updates);
const added = updates.filter(u => u.action === 'add').length;
const updated = updates.filter(u => u.action === 'update').length;
console.log(`缓存更新完成: 新增 ${added}, 更新 ${updated}`);
return { updated, added, errors: result.errors };
}
// 检查资源是否需要更新
async checkIfNeedsUpdate(cachedResponse, resource) {
// 检查ETag
if (resource.etag) {
const cachedETag = cachedResponse.headers.get('etag');
return cachedETag !== resource.etag;
}
// 检查Last-Modified
if (resource.lastModified) {
const cachedLastModified = cachedResponse.headers.get('last-modified');
return new Date(cachedLastModified) < new Date(resource.lastModified);
}
// 检查缓存时间
if (resource.maxAge) {
const cacheDate = cachedResponse.headers.get('date');
const age = Date.now() - new Date(cacheDate).getTime();
return age > resource.maxAge * 1000;
}
return false;
}
// 数组分块
chunkArray(array, chunkSize) {
const chunks = [];
for (let i = 0; i < array.length; i += chunkSize) {
chunks.push(array.slice(i, i + chunkSize));
}
return chunks;
}
}
// 使用示例
const cacheManager = new CacheBatchManager();
// 批量缓存静态资源
const staticResources = [
{ url: '/css/main.css' },
{ url: '/js/app.js' },
{ url: '/js/vendor.js' },
{ url: '/images/logo.png' },
{ url: '/images/hero.jpg' },
// ... 更多资源
];
cacheManager.batchCacheResources('static-v1', staticResources, {
batchSize: 10,
onProgress: (progress) => {
console.log(`缓存进度: ${progress.percentage.toFixed(1)}%`);
}
}).then(result => {
console.log('静态资源缓存完成:', result);
});
// 预加载关键资源
const criticalResources = [
{ url: '/api/user/profile', options: { credentials: 'include' } },
{ url: '/css/critical.css' },
{ url: '/js/critical.js' }
];
cacheManager.preloadCriticalResources(criticalResources);
3. 数据压缩与序列化优化
3.1 数据压缩策略
class DataCompressionManager {
constructor() {
this.compressionMethods = {
gzip: this.gzipCompress.bind(this),
lz4: this.lz4Compress.bind(this),
json: this.jsonOptimize.bind(this),
binary: this.binarySerialize.bind(this)
};
}
// 智能压缩选择
async smartCompress(data, options = {}) {
const {
method = 'auto',
threshold = 1024, // 1KB以上才压缩
target = 'storage' // storage | network
} = options;
const originalSize = this.getDataSize(data);
// 小数据不压缩
if (originalSize < threshold) {
return {
data,
compressed: false,
originalSize,
compressedSize: originalSize,
method: 'none'
};
}
let bestResult = null;
let bestRatio = 0;
// 自动选择最佳压缩方法
if (method === 'auto') {
const methods = target === 'network'
? ['gzip', 'json']
: ['gzip', 'lz4', 'json', 'binary'];
for (const methodName of methods) {
try {
const result = await this.compressWithMethod(data, methodName);
const ratio = (originalSize - result.compressedSize) / originalSize;
if (ratio > bestRatio) {
bestRatio = ratio;
bestResult = result;
}
} catch (error) {
console.warn(`压缩方法 ${methodName} 失败:`, error);
}
}
} else {
bestResult = await this.compressWithMethod(data, method);
}
// 如果压缩效果不好,返回原始数据
if (!bestResult || bestResult.compressedSize >= originalSize * 0.9) {
return {
data,
compressed: false,
originalSize,
compressedSize: originalSize,
method: 'none'
};
}
return bestResult;
}
// 使用指定方法压缩
async compressWithMethod(data, method) {
const originalSize = this.getDataSize(data);
const startTime = performance.now();
const compressedData = await this.compressionMethods[method](data);
const compressedSize = this.getDataSize(compressedData);
const compressionTime = performance.now() - startTime;
return {
data: compressedData,
compressed: true,
originalSize,
compressedSize,
method,
compressionTime,
ratio: (originalSize - compressedSize) / originalSize
};
}
// GZIP压缩
async gzipCompress(data) {
const stream = new CompressionStream('gzip');
const writer = stream.writable.getWriter();
const reader = stream.readable.getReader();
const chunks = [];
// 写入数据
const encoder = new TextEncoder();
const inputData = typeof data === 'string' ? data : JSON.stringify(data);
writer.write(encoder.encode(inputData));
writer.close();
// 读取压缩结果
let result;
while (!(result = await reader.read()).done) {
chunks.push(result.value);
}
// 合并chunks
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
const compressed = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
compressed.set(chunk, offset);
offset += chunk.length;
}
return {
type: 'gzip',
data: compressed,
metadata: {
originalType: typeof data,
timestamp: Date.now()
}
};
}
// GZIP解压
async gzipDecompress(compressedData) {
const stream = new DecompressionStream('gzip');
const writer = stream.writable.getWriter();
const reader = stream.readable.getReader();
const chunks = [];
// 写入压缩数据
writer.write(compressedData.data);
writer.close();
// 读取解压结果
let result;
while (!(result = await reader.read()).done) {
chunks.push(result.value);
}
// 合并并解码
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
const decompressed = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
decompressed.set(chunk, offset);
offset += chunk.length;
}
const decoder = new TextDecoder();
const text = decoder.decode(decompressed);
// 根据原始类型返回数据
return compressedData.metadata.originalType === 'string'
? text
: JSON.parse(text);
}
// JSON优化压缩
async jsonOptimize(data) {
if (typeof data !== 'object') {
return data;
}
// 移除空值和undefined
const cleaned = this.removeEmptyValues(data);
// 压缩键名
const { compressed, keyMap } = this.compressKeys(cleaned);
// 使用紧凑JSON格式
const jsonString = JSON.stringify(compressed);
return {
type: 'json-optimized',
data: jsonString,
keyMap,
metadata: {
originalKeys: Object.keys(data).length,
compressedKeys: Object.keys(keyMap).length
}
};
}
// 移除空值
removeEmptyValues(obj) {
if (Array.isArray(obj)) {
return obj.map(item => this.removeEmptyValues(item))
.filter(item => item !== null && item !== undefined);
}
if (typeof obj === 'object' && obj !== null) {
const cleaned = {};
for (const [key, value] of Object.entries(obj)) {
if (value !== null && value !== undefined && value !== '') {
const cleanedValue = this.removeEmptyValues(value);
if (cleanedValue !== null && cleanedValue !== undefined) {
cleaned[key] = cleanedValue;
}
}
}
return cleaned;
}
return obj;
}
// 压缩对象键名
compressKeys(obj) {
const keyMap = {};
let keyCounter = 0;
const compress = (item) => {
if (Array.isArray(item)) {
return item.map(compress);
}
if (typeof item === 'object' && item !== null) {
const compressed = {};
for (const [key, value] of Object.entries(item)) {
// 为长键名创建短别名
let compressedKey = key;
if (key.length > 3) {
if (!keyMap[key]) {
keyMap[key] = `k${keyCounter++}`;
}
compressedKey = keyMap[key];
}
compressed[compressedKey] = compress(value);
}
return compressed;
}
return item;
};
return {
compressed: compress(obj),
keyMap
};
}
// 二进制序列化
async binarySerialize(data) {
// 简化的二进制序列化实现
const buffer = new ArrayBuffer(1024 * 1024); // 1MB buffer
const view = new DataView(buffer);
let offset = 0;
const serialize = (value) => {
if (typeof value === 'number') {
view.setUint8(offset++, 1); // type: number
view.setFloat64(offset, value);
offset += 8;
} else if (typeof value === 'string') {
view.setUint8(offset++, 2); // type: string
const encoder = new TextEncoder();
const encoded = encoder.encode(value);
view.setUint32(offset, encoded.length);
offset += 4;
for (let i = 0; i < encoded.length; i++) {
view.setUint8(offset++, encoded[i]);
}
} else if (typeof value === 'boolean') {
view.setUint8(offset++, 3); // type: boolean
view.setUint8(offset++, value ? 1 : 0);
} else if (Array.isArray(value)) {
view.setUint8(offset++, 4); // type: array
view.setUint32(offset, value.length);
offset += 4;
value.forEach(serialize);
} else if (typeof value === 'object' && value !== null) {
view.setUint8(offset++, 5); // type: object
const keys = Object.keys(value);
view.setUint32(offset, keys.length);
offset += 4;
keys.forEach(key => {
serialize(key);
serialize(value[key]);
});
}
};
serialize(data);
return {
type: 'binary',
data: buffer.slice(0, offset),
size: offset
};
}
// 获取数据大小
getDataSize(data) {
if (data instanceof ArrayBuffer) {
return data.byteLength;
}
if (data instanceof Uint8Array) {
return data.length;
}
if (typeof data === 'string') {
return new TextEncoder().encode(data).length;
}
return new TextEncoder().encode(JSON.stringify(data)).length;
}
// 解压数据
async decompress(compressedData) {
switch (compressedData.type) {
case 'gzip':
return this.gzipDecompress(compressedData);
case 'json-optimized':
return this.jsonDecompress(compressedData);
case 'binary':
return this.binaryDeserialize(compressedData);
default:
return compressedData.data;
}
}
// JSON解压
jsonDecompress(compressedData) {
const parsed = JSON.parse(compressedData.data);
// 恢复键名
const decompress = (item) => {
if (Array.isArray(item)) {
return item.map(decompress);
}
if (typeof item === 'object' && item !== null) {
const decompressed = {};
for (const [key, value] of Object.entries(item)) {
// 查找原始键名
const originalKey = Object.keys(compressedData.keyMap)
.find(k => compressedData.keyMap[k] === key) || key;
decompressed[originalKey] = decompress(value);
}
return decompressed;
}
return item;
};
return decompress(parsed);
}
}
// 使用示例
const compressionManager = new DataCompressionManager();
// 压缩大型数据对象
const largeData = {
users: Array(1000).fill(null).map((_, i) => ({
id: i,
name: `User ${i}`,
email: `user${i}@example.com`,
profile: {
age: 20 + (i % 50),
city: `City ${i % 10}`,
preferences: {
theme: i % 2 ? 'dark' : 'light',
language: i % 3 ? 'en' : 'zh',
notifications: true
}
}
})),
metadata: {
version: '1.0',
timestamp: Date.now(),
source: 'user-management-system'
}
};
// 智能压缩
compressionManager.smartCompress(largeData, {
method: 'auto',
target: 'storage'
}).then(result => {
console.log('压缩结果:', {
method: result.method,
originalSize: `${(result.originalSize / 1024).toFixed(2)} KB`,
compressedSize: `${(result.compressedSize / 1024).toFixed(2)} KB`,
ratio: `${(result.ratio * 100).toFixed(2)}%`,
compressionTime: `${result.compressionTime.toFixed(2)} ms`
});
// 保存压缩数据
localStorage.setItem('compressed-data', JSON.stringify(result));
});
3.2 序列化优化
class SerializationOptimizer {
constructor() {
this.serializers = {
json: this.jsonSerializer.bind(this),
msgpack: this.msgpackSerializer.bind(this),
protobuf: this.protobufSerializer.bind(this),
custom: this.customSerializer.bind(this)
};
}
// 智能序列化选择
async optimizeSerialize(data, options = {}) {
const {
format = 'auto',
includeMetadata = true,
validateData = true
} = options;
if (validateData) {
this.validateData(data);
}
const results = [];
if (format === 'auto') {
// 测试所有序列化方法
for (const [name, serializer] of Object.entries(this.serializers)) {
try {
const startTime = performance.now();
const serialized = await serializer(data);
const endTime = performance.now();
results.push({
format: name,
data: serialized,
size: this.getSerializedSize(serialized),
time: endTime - startTime
});
} catch (error) {
console.warn(`序列化方法 ${name} 失败:`, error);
}
}
// 选择最优方法(综合考虑大小和速度)
const best = results.reduce((best, current) => {
const bestScore = best.size * 0.7 + best.time * 0.3;
const currentScore = current.size * 0.7 + current.time * 0.3;
return currentScore < bestScore ? current : best;
});
return {
...best,
metadata: includeMetadata ? {
originalSize: this.getDataSize(data),
allResults: results,
selectedReason: 'auto-optimization'
} : undefined
};
} else {
const serializer = this.serializers[format];
if (!serializer) {
throw new Error(`不支持的序列化格式: ${format}`);
}
const startTime = performance.now();
const serialized = await serializer(data);
const endTime = performance.now();
return {
format,
data: serialized,
size: this.getSerializedSize(serialized),
time: endTime - startTime,
metadata: includeMetadata ? {
originalSize: this.getDataSize(data)
} : undefined
};
}
}
// JSON序列化优化
jsonSerializer(data) {
// 自定义JSON序列化,处理特殊类型
const replacer = (key, value) => {
// 处理Date对象
if (value instanceof Date) {
return { __type: 'Date', value: value.toISOString() };
}
// 处理RegExp对象
if (value instanceof RegExp) {
return { __type: 'RegExp', source: value.source, flags: value.flags };
}
// 处理Map对象
if (value instanceof Map) {
return { __type: 'Map', entries: Array.from(value.entries()) };
}
// 处理Set对象
if (value instanceof Set) {
return { __type: 'Set', values: Array.from(value.values()) };
}
// 处理BigInt
if (typeof value === 'bigint') {
return { __type: 'BigInt', value: value.toString() };
}
return value;
};
return JSON.stringify(data, replacer);
}
// MessagePack序列化(简化实现)
msgpackSerializer(data) {
// 这里应该使用真正的MessagePack库
// 为了演示,使用简化的二进制格式
const buffer = new ArrayBuffer(1024 * 1024);
const view = new DataView(buffer);
let offset = 0;
const encode = (value) => {
if (value === null) {
view.setUint8(offset++, 0xc0); // nil
} else if (typeof value === 'boolean') {
view.setUint8(offset++, value ? 0xc3 : 0xc2); // true/false
} else if (typeof value === 'number') {
if (Number.isInteger(value) && value >= 0 && value < 128) {
view.setUint8(offset++, value); // positive fixint
} else {
view.setUint8(offset++, 0xcb); // float64
view.setFloat64(offset, value);
offset += 8;
}
} else if (typeof value === 'string') {
const encoder = new TextEncoder();
const encoded = encoder.encode(value);
if (encoded.length < 32) {
view.setUint8(offset++, 0xa0 | encoded.length); // fixstr
} else {
view.setUint8(offset++, 0xda); // str16
view.setUint16(offset, encoded.length);
offset += 2;
}
for (let i = 0; i < encoded.length; i++) {
view.setUint8(offset++, encoded[i]);
}
} else if (Array.isArray(value)) {
if (value.length < 16) {
view.setUint8(offset++, 0x90 | value.length); // fixarray
} else {
view.setUint8(offset++, 0xdc); // array16
view.setUint16(offset, value.length);
offset += 2;
}
value.forEach(encode);
} else if (typeof value === 'object') {
const keys = Object.keys(value);
if (keys.length < 16) {
view.setUint8(offset++, 0x80 | keys.length); // fixmap
} else {
view.setUint8(offset++, 0xde); // map16
view.setUint16(offset, keys.length);
offset += 2;
}
keys.forEach(key => {
encode(key);
encode(value[key]);
});
}
};
encode(data);
return {
type: 'msgpack',
data: buffer.slice(0, offset),
size: offset
};
}
// Protocol Buffers序列化(简化实现)
protobufSerializer(data) {
// 这里应该使用真正的protobuf库
// 为了演示,使用简化的格式
const fields = this.analyzeDataStructure(data);
const schema = this.generateProtobufSchema(fields);
return {
type: 'protobuf',
schema,
data: this.encodeWithSchema(data, schema),
metadata: {
fieldCount: fields.length,
schemaSize: JSON.stringify(schema).length
}
};
}
// 自定义序列化
customSerializer(data) {
// 针对特定数据结构的优化序列化
if (this.isUserProfileData(data)) {
return this.serializeUserProfile(data);
}
if (this.isTimeSeriesData(data)) {
return this.serializeTimeSeries(data);
}
if (this.isImageMetadata(data)) {
return this.serializeImageMetadata(data);
}
// 默认使用JSON
return this.jsonSerializer(data);
}
// 分析数据结构
analyzeDataStructure(data, path = '') {
const fields = [];
const analyze = (obj, currentPath) => {
if (typeof obj === 'object' && obj !== null && !Array.isArray(obj)) {
Object.keys(obj).forEach(key => {
const value = obj[key];
const fieldPath = currentPath ? `${currentPath}.${key}` : key;
fields.push({
path: fieldPath,
type: this.getFieldType(value),
required: value !== null && value !== undefined,
repeated: Array.isArray(value)
});
if (typeof value === 'object' && value !== null) {
analyze(value, fieldPath);
}
});
}
};
analyze(data, path);
return fields;
}
// 获取字段类型
getFieldType(value) {
if (value === null || value === undefined) return 'optional';
if (typeof value === 'boolean') return 'bool';
if (typeof value === 'number') {
return Number.isInteger(value) ? 'int32' : 'double';
}
if (typeof value === 'string') return 'string';
if (Array.isArray(value)) return 'repeated';
if (typeof value === 'object') return 'message';
return 'bytes';
}
// 用户配置文件序列化
serializeUserProfile(data) {
const buffer = new ArrayBuffer(1024);
const view = new DataView(buffer);
let offset = 0;
// 用户ID(4字节)
view.setUint32(offset, data.id || 0);
offset += 4;
// 用户名长度和内容
const nameBytes = new TextEncoder().encode(data.name || '');
view.setUint8(offset++, nameBytes.length);
for (let i = 0; i < nameBytes.length; i++) {
view.setUint8(offset++, nameBytes[i]);
}
// 邮箱长度和内容
const emailBytes = new TextEncoder().encode(data.email || '');
view.setUint8(offset++, emailBytes.length);
for (let i = 0; i < emailBytes.length; i++) {
view.setUint8(offset++, emailBytes[i]);
}
// 年龄(1字节)
view.setUint8(offset++, data.age || 0);
// 偏好设置(位标志)
let preferences = 0;
if (data.preferences) {
if (data.preferences.theme === 'dark') preferences |= 1;
if (data.preferences.notifications) preferences |= 2;
if (data.preferences.language === 'zh') preferences |= 4;
}
view.setUint8(offset++, preferences);
return {
type: 'user-profile',
data: buffer.slice(0, offset),
size: offset
};
}
// 时间序列数据序列化
serializeTimeSeries(data) {
const buffer = new ArrayBuffer(data.points.length * 12 + 16);
const view = new DataView(buffer);
let offset = 0;
// 头部信息
view.setUint32(offset, data.points.length); // 点数量
offset += 4;
view.setFloat64(offset, data.startTime || 0); // 开始时间
offset += 8;
view.setUint32(offset, data.interval || 1000); // 时间间隔
offset += 4;
// 数据点(时间戳 + 值)
data.points.forEach(point => {
view.setFloat64(offset, point.timestamp);
offset += 8;
view.setFloat32(offset, point.value);
offset += 4;
});
return {
type: 'time-series',
data: buffer.slice(0, offset),
size: offset,
metadata: {
pointCount: data.points.length,
compression: 'delta-encoding'
}
};
}
// 图片元数据序列化
serializeImageMetadata(data) {
const metadata = {
width: data.width || 0,
height: data.height || 0,
format: data.format || 'unknown',
size: data.size || 0,
created: data.created || Date.now(),
tags: data.tags || []
};
// 使用紧凑的二进制格式
const buffer = new ArrayBuffer(256);
const view = new DataView(buffer);
let offset = 0;
// 尺寸信息
view.setUint16(offset, metadata.width);
offset += 2;
view.setUint16(offset, metadata.height);
offset += 2;
// 文件大小
view.setUint32(offset, metadata.size);
offset += 4;
// 创建时间
view.setFloat64(offset, metadata.created);
offset += 8;
// 格式(枚举)
const formatMap = { 'jpeg': 1, 'png': 2, 'webp': 3, 'gif': 4 };
view.setUint8(offset++, formatMap[metadata.format] || 0);
// 标签
view.setUint8(offset++, metadata.tags.length);
metadata.tags.forEach(tag => {
const tagBytes = new TextEncoder().encode(tag);
view.setUint8(offset++, tagBytes.length);
for (let i = 0; i < tagBytes.length; i++) {
view.setUint8(offset++, tagBytes[i]);
}
});
return {
type: 'image-metadata',
data: buffer.slice(0, offset),
size: offset
};
}
// 数据类型检测
isUserProfileData(data) {
return data && typeof data === 'object' &&
'id' in data && 'name' in data && 'email' in data;
}
isTimeSeriesData(data) {
return data && typeof data === 'object' &&
Array.isArray(data.points) &&
data.points.every(p => 'timestamp' in p && 'value' in p);
}
isImageMetadata(data) {
return data && typeof data === 'object' &&
'width' in data && 'height' in data && 'format' in data;
}
// 数据验证
validateData(data) {
if (data === null || data === undefined) {
throw new Error('数据不能为空');
}
// 检查循环引用
try {
JSON.stringify(data);
} catch (error) {
if (error.message.includes('circular')) {
throw new Error('数据包含循环引用');
}
throw error;
}
// 检查数据大小
const size = this.getDataSize(data);
if (size > 100 * 1024 * 1024) { // 100MB
console.warn('数据过大,可能影响序列化性能');
}
}
// 获取数据大小
getDataSize(data) {
if (typeof data === 'string') {
return new TextEncoder().encode(data).length;
}
if (data instanceof ArrayBuffer) {
return data.byteLength;
}
if (data && typeof data === 'object') {
return new TextEncoder().encode(JSON.stringify(data)).length;
}
return 0;
}
// 获取序列化后大小
getSerializedSize(serialized) {
if (typeof serialized === 'string') {
return new TextEncoder().encode(serialized).length;
}
if (serialized instanceof ArrayBuffer) {
return serialized.byteLength;
}
if (serialized && typeof serialized === 'object' && serialized.data) {
return this.getSerializedSize(serialized.data);
}
return 0;
}
}
// 使用示例
const serializationOptimizer = new SerializationOptimizer();
// 测试不同类型的数据
const testData = {
userProfile: {
id: 12345,
name: 'John Doe',
email: 'john@example.com',
age: 30,
preferences: {
theme: 'dark',
notifications: true,
language: 'zh'
}
},
timeSeries: {
startTime: Date.now(),
interval: 1000,
points: Array(100).fill(null).map((_, i) => ({
timestamp: Date.now() + i * 1000,
value: Math.sin(i * 0.1) * 100
}))
},
imageMetadata: {
width: 1920,
height: 1080,
format: 'jpeg',
size: 2048576,
created: Date.now(),
tags: ['landscape', 'nature', 'sunset']
}
};
// 自动选择最优序列化方法
Object.keys(testData).forEach(async (key) => {
const data = testData[key];
const result = await serializationOptimizer.optimizeSerialize(data, {
format: 'auto',
includeMetadata: true
});
console.log(`${key} 序列化结果:`, {
format: result.format,
originalSize: `${(result.metadata.originalSize / 1024).toFixed(2)} KB`,
serializedSize: `${(result.size / 1024).toFixed(2)} KB`,
compressionRatio: `${((1 - result.size / result.metadata.originalSize) * 100).toFixed(2)}%`,
serializationTime: `${result.time.toFixed(2)} ms`
});
});
通过这些优化技术,我们可以根据不同的数据特点选择最适合的存储和序列化方案,从而获得最佳的性能表现。
记住,性能优化是一个持续的过程。在实际应用中,需要:
- 建立基准测试:了解当前性能水平
- 监控关键指标:跟踪存储操作的性能变化
- 逐步优化:一次优化一个方面,测量效果
- 根据数据调整:基于实际使用情况持续改进
这样才能构建出真正高性能的Web存储解决方案,为用户提供流畅的体验。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)