In front-end development applications, performance has always been a point of attention, but the most intuitive way to judge the performance of an application is to look at the speed of page opening. One way to speed up page response is to use caching. A good caching strategy can shorten the distance between page request resources, reduce latency, and reduce bandwidth and network load because cached files can be reused.

Common front-end caching technologies are not described here, but are enhanced based on Storage using the same API as Map.

If you don’t understand ECMAScript 6, please read it first

Here is the basic code, which will be enhanced

class MinCache {// Stores the data in the name specified in the local Cacheset(name, data) { try { uni.setStorageSync(name, Data)} catch (e) {console.log(e)}} get (name) {let data
    try {
      data = uni.getStorageSync(name)
    } catch (e) {
      console.log(e)
    }
    returnData} // Remove the specified key delete (name) {try {uni.removeStoragesync (name)} catch (e) {console.log(e)}} // return a Boolean value, Has (name) {const value try {const res = uni.getStorageInfosync () value = res.keys.includes(name)} catch (e) { console.log(e) }returnValue} // Clear the local data cacheclear () {
    try {
      uni.clearStorageSync()
    } catch (e) {
      console.log(e)
    }
  }
}

export default MinCacheCopy the code

We know that caching is often harmful, so it’s best to set a time limit for removing data.

Class cacheecell {constructor (data, timeout) {this.data = data This.timeout = timeout // The time when the object was created this.createTime = date.now ()}}Copy the code
  set (name, data, timeout = 1200) {
    const cachecell = new CacheCell(data, timeout)
    try {
      uni.setStorageSync(name, cachecell)
    } catch (e) {
      console.log(e)
    }
  }
  get (name) {
    let data = null
    try {
      data = uni.getStorageSync(name)
      if(! data)return null
      const currentTime = Date.now()
      const overTime = (currentTime - data.createTime) / 1000
      if(overTime > data.timeout) { try { uni.removeStorageSync(name) data = null } catch (e) { console.log(e) } } } catch (e) {  console.log(e) }return data
  }Copy the code

The expiration time cache can be used in most business scenarios.

Uni-app Storage is implemented differently at different ends:

  • The H5 terminal is localStorage. The browser limits the size to 5M. It is a cache concept and may be cleared

  • The App side is the original Plus. storage with no size limitation, not cache and persistence

  • Each small program has its own storage API. The data storage life cycle is consistent with the small program itself, that is, data is always available unless the user actively deletes it or the data is automatically cleaned after a certain period of time.

  • The maximum length of data stored by a single key in wechat applet is 1MB, and the maximum length of all data stored is 10MB.

  • After converting a single piece of data into a string, the maximum length of the string is 200*1024. For the same Alipay user, the total upper limit of the same small program cache is 10MB.

  • Baidu, toutiao small program documents do not specify size limits

H5 supports WebSQL, indexedDB, and sessionStorage. App side also supports SQLite, IO file and other local storage solutions.

We can see that Storage in some end of the size limit, in fact, we just want to cache the data, not necessarily persistent.

This means that it is ok to use Storage within the application life cycle, and it is not good to operate Storage directly.

We know that ES6 has maps for caching

The following code is wrapped based on Map

let cacheMap =  new Map()
let instance = null
let timeoutDefault = 1200

function isTimeout (name) {
  const data = cacheMap.get(name)
  if(! data)return true
  if (data.timeout === 0) return false
  const currentTime = Date.now()
  const overTime = (currentTime - data.createTime) / 1000
  if (overTime > data.timeout) {
    cacheMap.delete(name)
    return true
  }
  return false
}

class CacheCell {
  constructor (data, timeout) {
    this.data = data
    this.timeout = timeout
    this.createTime = Date.now()
  }
}

class Cache {
  set (name, data, timeout = timeoutDefault) {
    const cachecell = new CacheCell(data, timeout)
    return cacheMap.set(name, cachecell)
  }
  get (name) {
    return isTimeout(name) ? null : cacheMap.get(name).data
  }
  delete (name) {
    return cacheMap.delete(name)
  }
  has (name) {
    return! isTimeout(name) }clear () {
    return cacheMap.clear()
  }
  setTimeoutDefault (num) {
    if (timeoutDefault === 1200) {
      return timeoutDefault = num
    }
    throw Error('The cache can only set the default expiration time once')
  }
}

class ProxyCache {
  constructor () {
    return instance || (instance = new Cache())
  }
}

export default ProxyCacheCopy the code

Integrate Storage and Map encapsulated caches

So let’s analyze it

  • Storage and Map share the same API

    • Resolve the following underlined _ name on the cache to Storage, and Map also has a copy

  • Try not to operate Storage(slow read speed)

    • Storage must be loaded into Map when the application is initialized

  • Use it like a Vue plug-in

let cacheMap =  new Map()
let timeoutDefault = 1200

function isTimeout (name) {
  const data = cacheMap.get(name)
  if(! data)return true
  if (data.timeout === 0) return false 
  const currentTime = Date.now()
  const overTime = (currentTime - data.createTime) / 1000
  if (overTime > data.timeout) {
    cacheMap.delete(name)
    if (name.startsWith('_')) {
      try {
        uni.removeStorageSync(name)
      } catch (e) {
        console.log(e)
      }
    }
    return true
  }
  return false
}

class CacheCell {
  constructor (data, timeout) {
    this.data = data
    this.timeout = timeout
    this.createTime = Date.now()
  }
}

class MinCache {
  constructor (timeout) {
    try {
      const res = uni.getStorageInfoSync()
      res.keys.forEach(name => {
        try {
          const value = uni.getStorageSync(name)
          cacheMap.set(name, value)
        } catch (e) {
          console.log(e)
        }
      })
    } catch (e) {
      console.log(e)
    }
    timeoutDefault = timeout
  }
  set (name, data, timeout = timeoutDefault) {
    const cachecell = new CacheCell(data, timeout)
    let cache = null
    if (name.startsWith('_')) {
      try {
        uni.setStorageSync(name, cachecell)
        cache = cacheMap.set(name, cachecell)
      } catch (e) {
        console.log(e)
      }
    } else {
      cache = cacheMap.set(name, cachecell)
    }
    return cache
  }
  get (name) {
    return isTimeout(name) ? null : cacheMap.get(name).data
  }
  delete (name) {
    let value = false
    if (name.startsWith('_')) {
      try {
        uni.removeStorageSync(name)
        value = cacheMap.delete(name)
      } catch (e) {
        console.log(e)
      }
    } else {
      value = cacheMap.delete(name)
    }
    return value
  }
  has (name) {
    return! isTimeout(name) }clear () {
    let value = false
    try {
      uni.clearStorageSync()
      cacheMap.clear()
      value = true
    } catch (e) {
      console.log(e)
    }
    return value
  }
}

MinCache.install = function (Vue, {timeout = 1200} = {}) {
  Vue.prototype.$cache = new MinCache(timeout)
}

export default MinCacheCopy the code

Method of use

Name The name starting with underscore _ is cached to the Storage, and Map also has a copy

The event name parameter instructions The return value
set Name Cache key,data Cache data,timeout(unit: s) Cache duration. The default cache duration is 1200s. If timeout is set to 0, the cache is permanent Setting cached data Map collections
get Name Cache key Get data (null will be returned if cache expires) Returns the cached data data
has Name Cache key Check the value true/false
delete Name Cache key Delete the data true/false
clear Clear Storage and Map cache data true/false
Vue. Use (MinCache) // Set the default Cache time // vue.use (M)inCache, {timeout: 600})Copy the code
// 'name'Representations that do not begin with an underscore will be cached in the Map, and this will be valid for as long as the program lives.$cache.set('name'.'MinCache') // If the expiration time is set to 0, it will not expire.'test'It is not named with an underscore to indicate that this is permanently cached during the program life cycle.$cache.set('test'.'testdemo', 0) // If the expiration time is set to 0, it will not expire.'_imgURL'The name is underlined to indicate permanent cache to Storage this.$cache.set('_imgURL'.'data', 0)Copy the code
ImgURL = this. ImgURL = this.$cache.get('_imgURL')
this.name = this.$cache.get('name')
this.test = this.$cache.get('test')Copy the code

For details, see Github

Encapsulation of uni-APP routes