阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 持久化存储方案

持久化存储方案

作者:陈川 阅读数:64956人阅读 分类: Vue.js

本地存储方案

Vue.js 应用中常用的本地持久化存储方案包括 localStorage 和 sessionStorage。这两种方案都基于 Web Storage API,提供简单的键值对存储机制。

// 存储数据
localStorage.setItem('userToken', 'abc123def456')
sessionStorage.setItem('currentTab', 'profile')

// 获取数据
const token = localStorage.getItem('userToken')
const activeTab = sessionStorage.getItem('currentTab')

// 删除数据
localStorage.removeItem('userToken')
sessionStorage.clear()

localStorage 的特点是:

  • 存储容量约5MB
  • 数据永久保存,除非手动清除
  • 同源策略限制
  • 同步操作可能阻塞主线程

sessionStorage 与 localStorage 的主要区别在于:

  • 数据仅在当前会话有效
  • 标签页关闭后自动清除
  • 不同标签页间隔离

IndexedDB 方案

对于需要存储大量结构化数据的场景,IndexedDB 提供了更强大的解决方案:

// 打开或创建数据库
const request = indexedDB.open('MyDatabase', 1)

request.onupgradeneeded = (event) => {
  const db = event.target.result
  const store = db.createObjectStore('products', { keyPath: 'id' })
  store.createIndex('priceIdx', 'price', { unique: false })
}

request.onsuccess = (event) => {
  const db = event.target.result
  const transaction = db.transaction('products', 'readwrite')
  const store = transaction.objectStore('products')
  
  // 添加数据
  store.add({ id: 1, name: 'Laptop', price: 999 })
  
  // 查询数据
  const getRequest = store.get(1)
  getRequest.onsuccess = () => {
    console.log(getRequest.result)
  }
}

IndexedDB 的优势包括:

  • 支持事务操作
  • 支持索引查询
  • 存储容量远大于 localStorage
  • 异步操作不阻塞UI
  • 支持二进制数据存储

Vuex 持久化插件

在 Vuex 状态管理中,可以使用 vuex-persistedstate 插件实现状态持久化:

import createPersistedState from 'vuex-persistedstate'

const store = new Vuex.Store({
  // ...
  plugins: [
    createPersistedState({
      key: 'my-vuex-store',
      storage: window.localStorage,
      reducer: (state) => ({
        user: state.user,
        settings: state.settings
      }),
      paths: ['user.authToken']
    })
  ]
})

配置选项说明:

  • key: 存储使用的键名
  • storage: 指定存储介质(localStorage/sessionStorage)
  • reducer: 自定义需要持久化的状态
  • paths: 指定需要持久化的模块路径

Cookie 存储方案

虽然现代前端较少直接操作 Cookie,但在某些场景下仍然有用:

// 设置Cookie
document.cookie = `username=john; expires=${new Date(Date.now() + 86400000).toUTCString()}; path=/`

// 读取Cookie
function getCookie(name) {
  const value = `; ${document.cookie}`
  const parts = value.split(`; ${name}=`)
  if (parts.length === 2) return parts.pop().split(';').shift()
}

Cookie 的特点:

  • 每个域名下最多存储50个
  • 单个Cookie不超过4KB
  • 每次HTTP请求都会携带
  • 支持设置过期时间
  • 有同源策略限制

文件系统访问API

现代浏览器提供了 File System Access API,适合处理用户文件:

async function saveFile(content) {
  try {
    const handle = await window.showSaveFilePicker({
      types: [{
        description: 'Text Files',
        accept: { 'text/plain': ['.txt'] }
      }]
    })
    const writable = await handle.createWritable()
    await writable.write(content)
    await writable.close()
    return handle
  } catch (err) {
    console.error('Error saving file:', err)
  }
}

主要功能包括:

  • 读取本地文件内容
  • 保存修改到原文件
  • 创建新文件并保存
  • 获取目录内容列表
  • 需要用户主动触发

服务端同步存储

结合Axios实现与服务端的同步存储:

import axios from 'axios'

const api = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000
})

// 封装存储方法
const storage = {
  async set(key, value) {
    try {
      localStorage.setItem(key, JSON.stringify(value))
      await api.post('/sync', { key, value })
    } catch (error) {
      console.error('Sync failed:', error)
    }
  },
  
  async get(key) {
    const localValue = localStorage.getItem(key)
    if (!localValue) {
      try {
        const { data } = await api.get(`/sync?key=${key}`)
        return data.value
      } catch (error) {
        console.error('Fetch failed:', error)
        return null
      }
    }
    return JSON.parse(localValue)
  }
}

// 使用示例
storage.set('preferences', { theme: 'dark', fontSize: 14 })
  .then(() => storage.get('preferences'))
  .then(prefs => console.log(prefs))

加密存储方案

对于敏感数据,建议采用加密存储:

import CryptoJS from 'crypto-js'

const SECRET_KEY = 'my-secret-key-123'

const secureStorage = {
  encrypt(data) {
    return CryptoJS.AES.encrypt(JSON.stringify(data), SECRET_KEY).toString()
  },
  
  decrypt(ciphertext) {
    const bytes = CryptoJS.AES.decrypt(ciphertext, SECRET_KEY)
    return JSON.parse(bytes.toString(CryptoJS.enc.Utf8))
  },
  
  set(key, value) {
    localStorage.setItem(key, this.encrypt(value))
  },
  
  get(key) {
    const ciphertext = localStorage.getItem(key)
    return ciphertext ? this.decrypt(ciphertext) : null
  }
}

// 使用示例
secureStorage.set('auth', { token: 'xyz789', expires: 3600 })
const authData = secureStorage.get('auth')

存储策略选择

不同场景下的存储方案选择建议:

  1. 用户偏好设置:localStorage + Vuex持久化插件
  2. 购物车数据:sessionStorage + 服务端备份
  3. 大型数据集:IndexedDB
  4. 敏感信息:加密存储 + 短期Cookie
  5. 离线应用数据:IndexedDB + Service Worker缓存

性能优化技巧

存储操作性能优化建议:

// 批量操作替代多次单次操作
function batchSave(items) {
  const transaction = db.transaction('items', 'readwrite')
  const store = transaction.objectStore('items')
  
  items.forEach(item => {
    store.put(item)
  })
  
  return new Promise((resolve, reject) => {
    transaction.oncomplete = resolve
    transaction.onerror = reject
  })
}

// 使用Web Worker处理大型数据
const worker = new Worker('storage-worker.js')
worker.postMessage({
  action: 'BULK_INSERT',
  data: largeDataSet
})

其他优化手段:

  • 对频繁读取的数据添加内存缓存层
  • 使用debounce技术合并频繁的写入操作
  • 对大型数据分块存储和读取
  • 定期清理过期数据

跨标签页通信

利用存储事件实现标签页间通信:

// 发送方
localStorage.setItem('message', JSON.stringify({
  type: 'DATA_UPDATE',
  payload: { /* 数据 */ },
  timestamp: Date.now()
}))

// 接收方
window.addEventListener('storage', (event) => {
  if (event.key === 'message') {
    const message = JSON.parse(event.newValue)
    if (message.type === 'DATA_UPDATE') {
      // 处理数据更新
    }
  }
})

存储限制处理

处理存储空间不足的情况:

function checkStorageSpace() {
  if ('storage' in navigator && 'estimate' in navigator.storage) {
    return navigator.storage.estimate()
      .then(estimate => {
        const remaining = estimate.quota - estimate.usage
        return remaining > 1024 * 1024 // 保留1MB空间
      })
  }
  return Promise.resolve(true)
}

async function safeSetItem(key, value) {
  const hasSpace = await checkStorageSpace()
  if (!hasSpace) {
    await clearOldData()
  }
  localStorage.setItem(key, value)
}

function clearOldData() {
  // 实现按LRU策略清理旧数据
}

存储数据迁移

实现存储方案升级时的数据迁移:

function migrateLocalStorageToIndexedDB() {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open('AppDatabase', 2)
    
    request.onupgradeneeded = (event) => {
      const db = event.target.result
      if (!db.objectStoreNames.contains('legacyData')) {
        const store = db.createObjectStore('legacyData')
        
        // 迁移localStorage数据
        for (let i = 0; i < localStorage.length; i++) {
          const key = localStorage.key(i)
          store.put(localStorage.getItem(key), key)
        }
      }
    }
    
    request.onsuccess = () => {
      // 迁移完成后清理旧数据
      localStorage.clear()
      resolve()
    }
    
    request.onerror = reject
  })
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌