阿里云主机折上折
  • 微信号
Current Site:Index > Persistent storage solution

Persistent storage solution

Author:Chuan Chen 阅读数:64953人阅读 分类: Vue.js

Local Storage Solutions

Common local persistent storage solutions in Vue.js applications include localStorage and sessionStorage. Both are based on the Web Storage API and provide a simple key-value storage mechanism.

// Store data
localStorage.setItem('userToken', 'abc123def456')
sessionStorage.setItem('currentTab', 'profile')

// Retrieve data
const token = localStorage.getItem('userToken')
const activeTab = sessionStorage.getItem('currentTab')

// Delete data
localStorage.removeItem('userToken')
sessionStorage.clear()

Characteristics of localStorage:

  • Storage capacity of approximately 5MB
  • Data is permanently saved unless manually cleared
  • Restricted by same-origin policy
  • Synchronous operations may block the main thread

Key differences between sessionStorage and localStorage:

  • Data is only valid for the current session
  • Automatically cleared when the tab is closed
  • Isolated between different tabs

IndexedDB Solution

For scenarios requiring storage of large amounts of structured data, IndexedDB provides a more powerful solution:

// Open or create a database
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')
  
  // Add data
  store.add({ id: 1, name: 'Laptop', price: 999 })
  
  // Query data
  const getRequest = store.get(1)
  getRequest.onsuccess = () => {
    console.log(getRequest.result)
  }
}

Advantages of IndexedDB:

  • Supports transactional operations
  • Supports indexed queries
  • Storage capacity is much larger than localStorage
  • Asynchronous operations do not block the UI
  • Supports binary data storage

Vuex Persistence Plugin

For Vuex state management, the vuex-persistedstate plugin can be used to achieve state persistence:

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']
    })
  ]
})

Configuration options:

  • key: The key name used for storage
  • storage: Specifies the storage medium (localStorage/sessionStorage)
  • reducer: Customizes the state to be persisted
  • paths: Specifies the module paths to be persisted

Cookie Storage Solution

Although modern frontend development rarely directly manipulates cookies, they are still useful in certain scenarios:

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

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

Characteristics of cookies:

  • Maximum of 50 per domain
  • Single cookie size limited to 4KB
  • Included in every HTTP request
  • Supports expiration time settings
  • Restricted by same-origin policy

File System Access API

Modern browsers provide the File System Access API, suitable for handling user files:

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)
  }
}

Main features include:

  • Reading local file content
  • Saving modifications to the original file
  • Creating and saving new files
  • Listing directory contents
  • Requires user interaction

Server-Side Synchronized Storage

Combining Axios for synchronized storage with the server:

import axios from 'axios'

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

// Encapsulated storage methods
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)
  }
}

// Usage example
storage.set('preferences', { theme: 'dark', fontSize: 14 })
  .then(() => storage.get('preferences'))
  .then(prefs => console.log(prefs))

Encrypted Storage Solution

For sensitive data, encrypted storage is recommended:

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
  }
}

// Usage example
secureStorage.set('auth', { token: 'xyz789', expires: 3600 })
const authData = secureStorage.get('auth')

Storage Strategy Selection

Recommendations for storage solutions in different scenarios:

  1. User Preferences: localStorage + Vuex persistence plugin
  2. Shopping Cart Data: sessionStorage + server-side backup
  3. Large Datasets: IndexedDB
  4. Sensitive Information: Encrypted storage + short-term cookies
  5. Offline Application Data: IndexedDB + Service Worker caching

Performance Optimization Tips

Performance optimization suggestions for storage operations:

// Batch operations instead of multiple single operations
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
  })
}

// Use Web Workers for large data processing
const worker = new Worker('storage-worker.js')
worker.postMessage({
  action: 'BULK_INSERT',
  data: largeDataSet
})

Other optimization techniques:

  • Add an in-memory cache layer for frequently read data
  • Use debounce to merge frequent write operations
  • Store and read large data in chunks
  • Regularly clean up expired data

Cross-Tab Communication

Using storage events for communication between tabs:

// Sender
localStorage.setItem('message', JSON.stringify({
  type: 'DATA_UPDATE',
  payload: { /* data */ },
  timestamp: Date.now()
}))

// Receiver
window.addEventListener('storage', (event) => {
  if (event.key === 'message') {
    const message = JSON.parse(event.newValue)
    if (message.type === 'DATA_UPDATE') {
      // Handle data updates
    }
  }
})

Storage Limit Handling

Handling insufficient storage space:

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 // Reserve 1MB space
      })
  }
  return Promise.resolve(true)
}

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

function clearOldData() {
  // Implement LRU strategy for clearing old data
}

Storage Data Migration

Implementing data migration during storage solution upgrades:

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')
        
        // Migrate localStorage data
        for (let i = 0; i < localStorage.length; i++) {
          const key = localStorage.key(i)
          store.put(localStorage.getItem(key), key)
        }
      }
    }
    
    request.onsuccess = () => {
      // Clear old data after migration
      localStorage.clear()
      resolve()
    }
    
    request.onerror = reject
  })
}

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

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

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.