浏览器存储配额管理:智能清理与容量优化策略概述浏览器存储配额管理是现代Web应用面临的重要挑战。随着应用数据量的增长,如何有效管理存储空间、实现智能清理和容量优化变得至关重要。本文将深入探讨浏览器存储配额管理机制,实现智能清理算法与容量优化策略。存储配额检测与监控1. 配额检测管理器interface StorageQuota {
quota: number;
usage: number;
usageDetails?: Record<string, number>;
}
interface StorageEstimate extends StorageQuota {
available: number;
usagePercentage: number;
warningLevel: 'low' | 'medium' | 'high' | 'critical';
}
class StorageQuotaManager {
private estimates: Map<string, StorageEstimate>;
private listeners: Set<(estimate: StorageEstimate) => void>;
private monitoringInterval: number;
private updateInterval: NodeJS.Timeout | null;
constructor(monitoringInterval: number = 30000) { // 30秒
this.estimates = new Map();
this.listeners = new Set();
this.monitoringInterval = monitoringInterval;
this.updateInterval = null;
}
async initialize(): Promise<void> {
await this.updateAllEstimates();
this.startMonitoring();
}
async getEstimate(origin?: string): Promise<StorageEstimate> {
const targetOrigin = origin || window.location.origin;
if (!this.estimates.has(targetOrigin)) {
await this.updateEstimate(targetOrigin);
}
return this.estimates.get(targetOrigin)!;
}
private async updateEstimate(origin: string): Promise<void> {
try {
if ('storage' in navigator && 'estimate' in navigator.storage) {
const estimate = await navigator.storage.estimate();
const enhancedEstimate = this.enhanceEstimate(estimate, origin);
this.estimates.set(origin, enhancedEstimate);
this.notifyListeners(enhancedEstimate);
} else {
// 降级方案:使用传统API估算
const fallbackEstimate = await this.getFallbackEstimate(origin);
this.estimates.set(origin, fallbackEstimate);
this.notifyListeners(fallbackEstimate);
}
} catch (error) {
console.error('Failed to update storage estimate:', error);
throw new Error(`Storage estimate unavailable for ${origin}`);
}
}
private enhanceEstimate(estimate: StorageQuota, origin: string): StorageEstimate {
const available = estimate.quota - estimate.usage;
const usagePercentage = (estimate.usage / estimate.quota) * 100;
let warningLevel: 'low' | 'medium' | 'high' | 'critical';
if (usagePercentage >= 90) {
warningLevel = 'critical';
} else if (usagePercentage >= 75) {
warningLevel = 'high';
} else if (usagePercentage >= 50) {
warningLevel = 'medium';
} else {
warningLevel = 'low';
}
return {
...estimate,
available,
usagePercentage,
warningLevel
};
}
private async getFallbackEstimate(origin: string): Promise<StorageEstimate> {
// 模拟估算逻辑
const quota = this.estimateQuota();
const usage = await this.calculateUsage();
return this.enhanceEstimate({ quota, usage }, origin);
}
private estimateQuota(): number {
// 基于设备和浏览器的配额估算
const deviceInfo = this.getDeviceInfo();
const baseQuota = 50 * 1024 * 1024; // 50MB base
switch (deviceInfo.deviceType) {
case 'mobile':
return baseQuota * 0.5; // 25MB for mobile
case 'tablet':
return baseQuota * 0.8; // 40MB for tablet
case 'desktop':
return baseQuota * 2; // 100MB for desktop
default:
return baseQuota;
}
}
private async calculateUsage(): Promise<number> {
let totalUsage = 0;
// 计算localStorage使用量
try {
for (const key in localStorage) {
if (localStorage.hasOwnProperty(key)) {
totalUsage += (localStorage[key].length + key.length) * 2; // UTF-16
}
}
} catch (error) {
console.warn('localStorage usage calculation failed:', error);
}
// 计算IndexedDB使用量
try {
const dbUsage = await this.calculateIndexedDBUsage();
totalUsage += dbUsage;
} catch (error) {
console.warn('IndexedDB usage calculation failed:', error);
}
// 计算Cache Storage使用量
try {
const cacheUsage = await this.calculateCacheStorageUsage();
totalUsage += cacheUsage;
} catch (error) {
console.warn('Cache Storage usage calculation failed:', error);
}
return totalUsage;
}
private async calculateIndexedDBUsage(): Promise<number> {
return new Promise((resolve) => {
let totalSize = 0;
const request = indexedDB.databases();
request.then(async (databases) => {
for (const dbInfo of databases) {
try {
const db = await this.openDatabase(dbInfo.name);
const size = await this.calculateDatabaseSize(db);
totalSize += size;
db.close();
} catch (error) {
console.warn(`Failed to calculate size for database ${dbInfo.name}:`, error);
}
}
resolve(totalSize);
}).catch(() => resolve(0));
});
}
private async calculateCacheStorageUsage(): Promise<number> {
try {
const cacheNames = await caches.keys();
let totalSize = 0;
for (const cacheName of cacheNames) {
const cache = await caches.open(cacheName);
const requests = await cache.keys();
for (const request of requests) {
const response = await cache.match(request);
if (response) {
const blob = await response.blob();
totalSize += blob.size;
}
}
}
return totalSize;
} catch (error) {
console.warn('Cache Storage calculation failed:', error);
return 0;
}
}
private async openDatabase(name: string): Promise<IDBDatabase> {
return new Promise((resolve, reject) => {
const request = indexedDB.open(name);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
private async calculateDatabaseSize(db: IDBDatabase): Promise<number> {
return new Promise((resolve) => {
let totalSize = 0;
const transaction = db.transaction(db.objectStoreNames, 'readonly');
let completedStores = 0;
const totalStores = db.objectStoreNames.length;
if (totalStores === 0) {
resolve(0);
return;
}
for (const storeName of db.objectStoreNames) {
const objectStore = transaction.objectStore(storeName);
const countRequest = objectStore.count();
countRequest.onsuccess = () => {
// 粗略估算:每个记录平均1KB
totalSize += countRequest.result * 1024;
completedStores++;
if (completedStores === totalStores) {
resolve(totalSize);
}
};
countRequest.onerror = () => {
completedStores++;
if (completedStores === totalStores) {
resolve(totalSize);
}
};
}
});
}
private getDeviceInfo(): DeviceInfo {
const userAgent = navigator.userAgent;
const width = window.innerWidth;
let deviceType: 'mobile' | 'tablet' | 'desktop';
if (width <= 768) {
deviceType = 'mobile';
} else if (width <= 1024) {
deviceType = 'tablet';
} else {
deviceType = 'desktop';
}
return {
deviceType,
userAgent,
screenWidth: width,
memory: (navigator as any).deviceMemory,
cores: navigator.hardwareConcurrency
};
}
private startMonitoring(): void {
this.updateInterval = setInterval(async () => {
for (const origin of this.estimates.keys()) {
await this.updateEstimate(origin);
}
}, this.monitoringInterval);
}
stopMonitoring(): void {
if (this.updateInterval) {
clearInterval(this.updateInterval);
this.updateInterval = null;
}
}
subscribe(listener: (estimate: StorageEstimate) => void): () => void {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
private notifyListeners(estimate: StorageEstimate): void {
this.listeners.forEach(listener => {
try {
listener(estimate);
} catch (error) {
console.error('Error in storage quota listener:', error);
}
});
}
}
2. 智能清理策略引擎interface CleanupStrategy {
name: string;
priority: number;
canClean(item: StorageItem): boolean;
clean(items: StorageItem[]): Promise<CleanupResult>;
}
interface StorageItem {
key: string;
size: number;
lastAccessed: number;
priority: number;
type: 'localStorage' | 'indexedDB' | 'cache' | 'sessionStorage';
metadata?: Record<string, any>;
}
interface CleanupResult {
cleanedItems: number;
freedSpace: number;
errors: string[];
duration: number;
}
class IntelligentCleanupEngine {
private strategies: CleanupStrategy[];
private storageAnalyzer: StorageAnalyzer;
private cleanupHistory: CleanupHistory[];
constructor() {
this.strategies = [];
this.storageAnalyzer = new StorageAnalyzer();
this.cleanupHistory = [];
this.initializeDefaultStrategies();
}
private initializeDefaultStrategies(): void {
// LRU清理策略
this.addStrategy(new LRUCleanupStrategy());
// 优先级清理策略
this.addStrategy(new PriorityCleanupStrategy());
// 过期数据清理策略
this.addStrategy(new ExpirationCleanupStrategy());
// 大文件清理策略
this.addStrategy(new LargeFileCleanupStrategy());
// 临时数据清理策略
this.addStrategy(new TemporaryDataCleanupStrategy());
}
addStrategy(strategy: CleanupStrategy): void {
this.strategies.push(strategy);
this.strategies.sort((a, b) => b.priority - a.priority);
}
async performCleanup(
targetSize: number,
options: CleanupOptions = {}
): Promise<CleanupResult> {
const startTime = performance.now();
const items = await this.storageAnalyzer.analyzeStorage();
const currentSize = items.reduce((sum, item) => sum + item.size, 0);
if (currentSize <= targetSize) {
return {
cleanedItems: 0,
freedSpace: 0,
errors: [],
duration: performance.now() - startTime
};
}
const requiredCleanup = currentSize - targetSize;
let totalCleaned = 0;
let totalFreed = 0;
const errors: string[] = [];
// 按策略优先级执行清理
for (const strategy of this.strategies) {
if (totalFreed >= requiredCleanup) break;
const cleanableItems = items.filter(item =>
strategy.canClean(item) && !this.isItemProtected(item, options.protectedItems)
);
try {
const result = await strategy.clean(cleanableItems);
totalCleaned += result.cleanedItems;
totalFreed += result.freedSpace;
errors.push(...result.errors);
} catch (error) {
errors.push(`Strategy ${strategy.name} failed: ${error}`);
}
}
const duration = performance.now() - startTime;
const cleanupResult: CleanupResult = {
cleanedItems: totalCleaned,
freedSpace: totalFreed,
errors,
duration
};
this.recordCleanupHistory(cleanupResult);
return cleanupResult;
}
private isItemProtected(item: StorageItem, protectedItems?: string[]): boolean {
if (!protectedItems) return false;
return protectedItems.includes(item.key);
}
private recordCleanupHistory(result: CleanupResult): void {
this.cleanupHistory.push({
...result,
timestamp: Date.now()
});
// 保留最近100条记录
if (this.cleanupHistory.length > 100) {
this.cleanupHistory = this.cleanupHistory.slice(-100);
}
}
getCleanupHistory(): CleanupHistory[] {
return [...this.cleanupHistory];
}
predictCleanupEffect(itemsToClean: StorageItem[]): PredictedEffect {
const totalSize = itemsToClean.reduce((sum, item) => sum + item.size, 0);
const estimatedTime = this.estimateCleanupTime(itemsToClean.length);
const riskLevel = this.assessCleanupRisk(itemsToClean);
return {
freedSpace: totalSize,
estimatedTime,
riskLevel,
recommendations: this.generateRecommendations(itemsToClean)
};
}
private estimateCleanupTime(itemCount: number): number {
// 基于历史数据估算清理时间
const avgTimePerItem = 10; // 平均每个项目10ms
return itemCount * avgTimePerItem;
}
private assessCleanupRisk(items: StorageItem[]): 'low' | 'medium' | 'high' {
const hasHighPriorityItems = items.some(item => item.priority >= 8);
const hasRecentItems = items.some(item =>
Date.now() - item.lastAccessed < 24 * 60 * 60 * 1000
);
const hasLargeItems = items.some(item => item.size > 10 * 1024 * 1024); // 10MB
if (hasHighPriorityItems || (hasRecentItems && hasLargeItems)) {
return 'high';
} else if (hasRecentItems || hasLargeItems) {
return 'medium';
} else {
return 'low';
}
}
private generateRecommendations(items: StorageItem[]): string[] {
const recommendations: string[] = [];
if (items.some(item => item.priority >= 8)) {
recommendations.push('包含高优先级项目,建议谨慎清理');
}
if (items.some(item => Date.now() - item.lastAccessed < 60 * 60 * 1000)) {
recommendations.push('包含最近访问的项目,可能影响用户体验');
}
if (items.some(item => item.size > 50 * 1024 * 1024)) {
recommendations.push('包含大文件,清理可能释放大量空间');
}
return recommendations;
}
}
// LRU清理策略
class LRUCleanupStrategy implements CleanupStrategy {
name = 'LRU (Least Recently Used)';
priority = 100;
canClean(item: StorageItem): boolean {
// 可以清理任何类型的项目
return true;
}
async clean(items: StorageItem[]): Promise<CleanupResult> {
const startTime = performance.now();
const cleanedItems: StorageItem[] = [];
const errors: string[] = [];
// 按最后访问时间排序(最久未使用的优先清理)
const sortedItems = [...items].sort((a, b) => a.lastAccessed - b.lastAccessed);
for (const item of sortedItems) {
try {
await this.cleanItem(item);
cleanedItems.push(item);
} catch (error) {
errors.push(`Failed to clean ${item.key}: ${error}`);
}
}
const totalFreed = cleanedItems.reduce((sum, item) => sum + item.size, 0);
const duration = performance.now() - startTime;
return {
cleanedItems: cleanedItems.length,
freedSpace: totalFreed,
errors,
duration
};
}
private async cleanItem(item: StorageItem): Promise<void> {
switch (item.type) {
case 'localStorage':
localStorage.removeItem(item.key);
break;
case 'sessionStorage':
sessionStorage.removeItem(item.key);
break;
case 'indexedDB':
await this.cleanIndexedDB(item);
break;
case 'cache':
await this.cleanCache(item);
break;
default:
throw new Error(`Unknown storage type: ${item.type}`);
}
}
private async cleanIndexedDB(item: StorageItem): Promise<void> {
return new Promise((resolve, reject) => {
const dbName = item.metadata?.dbName;
const storeName = item.metadata?.storeName;
if (!dbName || !storeName) {
reject(new Error('Missing database or store name'));
return;
}
const request = indexedDB.open(dbName);
request.onsuccess = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
if (item.metadata?.key !== undefined) {
// 删除特定记录
const transaction = db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const deleteRequest = store.delete(item.metadata.key);
deleteRequest.onsuccess = () => resolve();
deleteRequest.onerror = () => reject(deleteRequest.error);
} else {
// 清空整个存储
const transaction = db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const clearRequest = store.clear();
clearRequest.onsuccess = () => resolve();
clearRequest.onerror = () => reject(clearRequest.error);
}
};
request.onerror = () => reject(request.error);
});
}
private async cleanCache(item: StorageItem): Promise<void> {
const cacheName = item.metadata?.cacheName;
if (!cacheName) {
throw new Error('Missing cache name');
}
const cache = await caches.open(cacheName);
if (item.metadata?.url) {
// 删除特定缓存
await cache.delete(item.metadata.url);
} else {
// 清空整个缓存
const requests = await cache.keys();
await Promise.all(requests.map(request => cache.delete(request)));
}
}
}
// 优先级清理策略
class PriorityCleanupStrategy implements CleanupStrategy {
name = 'Priority-based';
priority = 90;
canClean(item: StorageItem): boolean {
// 只清理优先级低于5的项目
return item.priority < 5;
}
async clean(items: StorageItem[]): Promise<CleanupResult> {
const startTime = performance.now();
const cleanableItems = items.filter(item => this.canClean(item));
// 按优先级排序(优先级低的优先清理)
const sortedItems = cleanableItems.sort((a, b) => a.priority - b.priority);
const cleanedItems: StorageItem[] = [];
const errors: string[] = [];
for (const item of sortedItems) {
try {
await this.cleanItem(item);
cleanedItems.push(item);
} catch (error) {
errors.push(`Failed to clean ${item.key}: ${error}`);
}
}
const totalFreed = cleanedItems.reduce((sum, item) => sum + item.size, 0);
const duration = performance.now() - startTime;
return {
cleanedItems: cleanedItems.length,
freedSpace: totalFreed,
errors,
duration
};
}
private async cleanItem(item: StorageItem): Promise<void> {
// 实现与LRU策略类似的清理逻辑
const lruStrategy = new LRUCleanupStrategy();
await lruStrategy.clean([item]);
}
}
3. 智能容量优化器interface OptimizationStrategy {
name: string;
optimize(items: StorageItem[]): Promise<OptimizationResult>;
}
interface OptimizationResult {
optimizedItems: number;
spaceSaved: number;
compressionRatio: number;
duration: number;
}
class SmartCapacityOptimizer {
private strategies: OptimizationStrategy[];
private compressionManager: CompressionManager;
private deduplicationEngine: DeduplicationEngine;
constructor() {
this.strategies = [];
this.compressionManager = new CompressionManager();
this.deduplicationEngine = new DeduplicationEngine();
this.initializeStrategies();
}
private initializeStrategies(): void {
this.strategies.push(new CompressionOptimizationStrategy(this.compressionManager));
this.strategies.push(new DeduplicationOptimizationStrategy(this.deduplicationEngine));
this.strategies.push(new FormatOptimizationStrategy());
this.strategies.push(new MetadataOptimizationStrategy());
}
async optimizeStorage(items: StorageItem[]): Promise<OptimizationResult> {
const startTime = performance.now();
let totalOptimized = 0;
let totalSaved = 0;
let totalCompressionRatio = 0;
for (const strategy of this.strategies) {
try {
const result = await strategy.optimize(items);
totalOptimized += result.optimizedItems;
totalSaved += result.spaceSaved;
totalCompressionRatio += result.compressionRatio;
} catch (error) {
console.error(`Optimization strategy ${strategy.name} failed:`, error);
}
}
const duration = performance.now() - startTime;
const avgCompressionRatio = totalCompressionRatio / this.strategies.length;
return {
optimizedItems: totalOptimized,
spaceSaved: totalSaved,
compressionRatio: avgCompressionRatio,
duration
};
}
async autoOptimize(targetRatio: number = 0.8): Promise<AutoOptimizationResult> {
const items = await this.storageAnalyzer.analyzeStorage();
const currentUsage = items.reduce((sum, item) => sum + item.size, 0);
const optimizationResult = await this.optimizeStorage(items);
const newUsage = currentUsage - optimizationResult.spaceSaved;
const achievedRatio = newUsage / currentUsage;
return {
...optimizationResult,
targetRatio,
achievedRatio,
success: achievedRatio <= targetRatio,
recommendations: this.generateOptimizationRecommendations(optimizationResult)
};
}
private generateOptimizationRecommendations(result: OptimizationResult): string[] {
const recommendations: string[] = [];
if (result.compressionRatio > 0.5) {
recommendations.push('压缩效果显著,建议继续使用压缩策略');
}
if (result.spaceSaved > 10 * 1024 * 1024) { // 10MB
recommendations.push('优化节省了大量空间,考虑定期进行优化');
}
if (result.duration > 5000) { // 5秒
recommendations.push('优化耗时较长,建议在后台或低峰期执行');
}
return recommendations;
}
}
// 压缩优化策略
class CompressionOptimizationStrategy implements OptimizationStrategy {
name = 'Compression';
constructor(private compressionManager: CompressionManager) {}
async optimize(items: StorageItem[]): Promise<OptimizationResult> {
const compressibleItems = items.filter(item =>
this.isCompressible(item) && item.size > 1024 // 只压缩大于1KB的项目
);
let totalSaved = 0;
let totalCompressed = 0;
for (const item of compressibleItems) {
try {
const originalData = await this.getItemData(item);
const compressedData = await this.compressionManager.compress(originalData);
const saved = originalData.byteLength - compressedData.byteLength;
if (saved > 0) {
await this.saveCompressedItem(item, compressedData);
totalSaved += saved;
totalCompressed++;
}
} catch (error) {
console.warn(`Failed to compress ${item.key}:`, error);
}
}
const compressionRatio = totalCompressed > 0 ? totalSaved / compressibleItems.reduce((sum, item) => sum + item.size, 0) : 0;
return {
optimizedItems: totalCompressed,
spaceSaved: totalSaved,
compressionRatio,
duration: 0 // 将在上层计算
};
}
private isCompressible(item: StorageItem): boolean {
// 文本、JSON、XML等格式可以压缩
const compressibleTypes = ['text/plain', 'application/json', 'text/xml', 'text/css', 'text/javascript'];
return compressibleTypes.includes(item.metadata?.contentType);
}
private async getItemData(item: StorageItem): Promise<ArrayBuffer> {
// 根据项目类型获取数据
switch (item.type) {
case 'localStorage':
case 'sessionStorage':
return new TextEncoder().encode(localStorage.getItem(item.key) || '').buffer;
case 'indexedDB':
return await this.getIndexedDBData(item);
case 'cache':
return await this.getCacheData(item);
default:
throw new Error(`Unsupported item type: ${item.type}`);
}
}
private async saveCompressedItem(item: StorageItem, compressedData: ArrayBuffer): Promise<void> {
// 保存压缩后的数据,并标记为已压缩
// 具体实现取决于存储类型
}
}
4. 配额预警系统interface QuotaAlert {
id: string;
type: 'warning' | 'critical' | 'emergency';
threshold: number;
message: string;
actions: AlertAction[];
timestamp: number;
}
interface AlertAction {
id: string;
label: string;
action: () => Promise<void>;
type: 'immediate' | 'scheduled';
}
class QuotaAlertSystem {
private alerts: Map<string, QuotaAlert>;
private activeAlerts: Set<string>;
private listeners: Set<(alert: QuotaAlert) => void>;
private quotaManager: StorageQuotaManager;
private cleanupEngine: IntelligentCleanupEngine;
constructor(
quotaManager: StorageQuotaManager,
cleanupEngine: IntelligentCleanupEngine
) {
this.alerts = new Map();
this.activeAlerts = new Set();
this.listeners = new Set();
this.quotaManager = quotaManager;
this.cleanupEngine = cleanupEngine;
this.initializeDefaultAlerts();
}
private initializeDefaultAlerts(): void {
// 警告级别 - 使用率75%
this.addAlert({
id: 'quota-warning',
type: 'warning',
threshold: 75,
message: '存储空间使用率已达到75%,建议进行清理',
actions: [
{
id: 'analyze-usage',
label: '分析使用情况',
action: async () => {
const estimate = await this.quotaManager.getEstimate();
console.log('Current usage analysis:', estimate);
},
type: 'immediate'
},
{
id: 'schedule-cleanup',
label: '计划清理',
action: async () => {
// 安排后台清理任务
setTimeout(async () => {
await this.performAutomaticCleanup(60); // 清理到60%使用率
}, 5000);
},
type: 'scheduled'
}
],
timestamp: Date.now()
});
// 严重级别 - 使用率90%
this.addAlert({
id: 'quota-critical',
type: 'critical',
threshold: 90,
message: '存储空间使用率已达到90%,需要立即清理',
actions: [
{
id: 'immediate-cleanup',
label: '立即清理',
action: async () => {
await this.performAutomaticCleanup(70); // 清理到70%使用率
},
type: 'immediate'
},
{
id: 'optimize-storage',
label: '优化存储',
action: async () => {
const optimizer = new SmartCapacityOptimizer();
await optimizer.autoOptimize(0.8);
},
type: 'immediate'
}
],
timestamp: Date.now()
});
// 紧急级别 - 使用率95%
this.addAlert({
id: 'quota-emergency',
type: 'emergency',
threshold: 95,
message: '存储空间使用率已达到95%,必须立即采取行动',
actions: [
{
id: 'emergency-cleanup',
label: '紧急清理',
action: async () => {
await this.performEmergencyCleanup();
},
type: 'immediate'
},
{
id: 'clear-temp-data',
label: '清除临时数据',
action: async () => {
await this.clearTemporaryData();
},
type: 'immediate'
}
],
timestamp: Date.now()
});
}
addAlert(alert: QuotaAlert): void {
this.alerts.set(alert.id, alert);
}
async checkAndTriggerAlerts(estimate: StorageEstimate): Promise<void> {
const usagePercentage = estimate.usagePercentage;
for (const [alertId, alert] of this.alerts) {
if (usagePercentage >= alert.threshold && !this.activeAlerts.has(alertId)) {
await this.triggerAlert(alert, estimate);
} else if (usagePercentage < alert.threshold && this.activeAlerts.has(alertId)) {
this.dismissAlert(alertId);
}
}
}
private async triggerAlert(alert: QuotaAlert, estimate: StorageEstimate): Promise<void> {
this.activeAlerts.add(alert.id);
// 显示通知
await this.showNotification(alert, estimate);
// 记录日志
this.logAlert(alert, estimate);
// 通知监听器
this.notifyListeners(alert);
// 执行自动操作
await this.executeAutoActions(alert);
}
private dismissAlert(alertId: string): void {
this.activeAlerts.delete(alertId);
console.log(`Alert ${alertId} dismissed`);
}
private async showNotification(alert: QuotaAlert, estimate: StorageEstimate): Promise<void> {
if ('Notification' in window && Notification.permission === 'granted') {
new Notification(`存储空间${alert.type}`, {
body: `${alert.message} (当前使用率: ${estimate.usagePercentage.toFixed(1)}%)`,
icon: '/icons/storage-alert.png',
tag: alert.id,
requireInteraction: alert.type === 'emergency'
});
}
}
private logAlert(alert: QuotaAlert, estimate: StorageEstimate): void {
console.warn(`[${alert.type.toUpperCase()}] ${alert.message}`, {
alertId: alert.id,
usagePercentage: estimate.usagePercentage,
usage: estimate.usage,
quota: estimate.quota,
timestamp: new Date().toISOString()
});
}
private notifyListeners(alert: QuotaAlert): void {
this.listeners.forEach(listener => {
try {
listener(alert);
} catch (error) {
console.error('Error in alert listener:', error);
}
});
}
private async executeAutoActions(alert: QuotaAlert): Promise<void> {
const autoActions = alert.actions.filter(action => action.type === 'immediate');
for (const action of autoActions) {
try {
console.log(`Executing auto action: ${action.label}`);
await action.action();
} catch (error) {
console.error(`Auto action failed: ${action.id}`, error);
}
}
}
private async performAutomaticCleanup(targetUsagePercentage: number): Promise<void> {
const estimate = await this.quotaManager.getEstimate();
const targetSize = (estimate.quota * targetUsagePercentage) / 100;
console.log(`Performing automatic cleanup to reach ${targetUsagePercentage}% usage`);
const result = await this.cleanupEngine.performCleanup(targetSize);
console.log('Automatic cleanup completed:', {
cleanedItems: result.cleanedItems,
freedSpace: this.formatBytes(result.freedSpace),
duration: `${result.duration.toFixed(2)}ms`
});
}
private async performEmergencyCleanup(): Promise<void> {
console.log('Performing emergency cleanup...');
// 获取当前使用情况
const estimate = await this.quotaManager.getEstimate();
const emergencyTarget = estimate.quota * 0.6; // 目标60%使用率
// 执行激进清理
const result = await this.cleanupEngine.performCleanup(emergencyTarget, {
aggressive: true,
includeTemporary: true,
includeCache: true
});
// 如果清理效果不佳,执行更激进的措施
if (result.freedSpace < estimate.usage * 0.2) {
await this.performAggressiveCleanup();
}
console.log('Emergency cleanup completed:', result);
}
private async performAggressiveCleanup(): Promise<void> {
console.log('Performing aggressive cleanup...');
// 清理IndexedDB中的非关键数据
await this.clearNonCriticalIndexedDB();
// 清理缓存存储
await this.clearAllCache();
// 清理localStorage中的非必要数据
await this.clearNonEssentialLocalStorage();
}
private async clearTemporaryData(): Promise<void> {
const tempPatterns = [
/^temp_/,
/^cache_/,
/^session_/,
/_tmp$/,
/_temp$/
];
// 清理localStorage中的临时数据
for (const key in localStorage) {
if (tempPatterns.some(pattern => pattern.test(key))) {
localStorage.removeItem(key);
}
}
// 清理sessionStorage
sessionStorage.clear();
console.log('Temporary data cleared');
}
private async clearNonCriticalIndexedDB(): Promise<void> {
try {
const databases = await indexedDB.databases();
const nonCriticalDBs = databases.filter(db =>
!db.name?.includes('critical') && !db.name?.includes('essential')
);
for (const db of nonCriticalDBs) {
if (db.name) {
indexedDB.deleteDatabase(db.name);
}
}
console.log(`Cleared ${nonCriticalDBs.length} non-critical databases`);
} catch (error) {
console.error('Failed to clear non-critical IndexedDB:', error);
}
}
private async clearAllCache(): Promise<void> {
try {
const cacheNames = await caches.keys();
await Promise.all(cacheNames.map(name => caches.delete(name)));
console.log(`Cleared ${cacheNames.length} cache storages`);
} catch (error) {
console.error('Failed to clear cache storages:', error);
}
}
private async clearNonEssentialLocalStorage(): Promise<void> {
const essentialKeys = [
'user_token',
'user_preferences',
'app_config',
'authentication'
];
const keysToRemove: string[] = [];
for (const key in localStorage) {
if (!essentialKeys.includes(key)) {
keysToRemove.push(key);
}
}
keysToRemove.forEach(key => localStorage.removeItem(key));
console.log(`Cleared ${keysToRemove.length} non-essential localStorage items`);
}
subscribe(listener: (alert: QuotaAlert) => void): () => void {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
private formatBytes(bytes: number): string {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
}
// 使用示例
class StorageQuotaDemo {
private quotaManager: StorageQuotaManager;
private cleanupEngine: IntelligentCleanupEngine;
private optimizer: SmartCapacityOptimizer;
private alertSystem: QuotaAlertSystem;
constructor() {
this.quotaManager = new StorageQuotaManager();
this.cleanupEngine = new IntelligentCleanupEngine();
this.optimizer = new SmartCapacityOptimizer();
this.alertSystem = new QuotaAlertSystem(this.quotaManager, this.cleanupEngine);
}
async initialize(): Promise<void> {
await this.quotaManager.initialize();
// 设置配额监控
this.quotaManager.subscribe(async (estimate) => {
await this.alertSystem.checkAndTriggerAlerts(estimate);
});
console.log('Storage quota management system initialized');
}
async demonstrateCleanup(): Promise<void> {
const estimate = await this.quotaManager.getEstimate();
console.log('Current storage usage:', estimate);
// 执行智能清理
const targetSize = estimate.usage * 0.7; // 目标减少到70%
const cleanupResult = await this.cleanupEngine.performCleanup(targetSize);
console.log('Cleanup result:', cleanupResult);
}
async demonstrateOptimization(): Promise<void> {
const result = await this.optimizer.autoOptimize(0.8);
console.log('Optimization result:', result);
}
}
总结浏览器存储配额管理是现代Web应用必须面对的重要挑战。通过实现智能清理算法、容量优化策略和配额预警系统,我们可以:智能监控:实时监控存储使用情况,提供准确的配额估算主动清理:基于多种策略的智能清理,确保存储空间的有效利用容量优化:通过压缩、去重等技术手段最大化存储效率预警机制:多级别的配额预警,防止存储空间耗尽自动化管理:自动执行清理和优化任务,减少人工干预这套完整的存储配额管理体系能够显著提升Web应用的可靠性和用户体验。

发表评论 取消回复