This article mainly solves the problem that native localStorage cannot set expiration time, and through encapsulation, to achieve a convenient operation, powerful localStorage library, some basic ideas and modes about library encapsulation, I will use before writingHow to write your own JS library in less than 200 lines of codeIn a similar way, interested friends can learn and communicate.

Design ideas

We will extend the localStorage raw API to support expiration time, callback after completion of the operation. At the end of this article, I’ll give you the completion code for the library, and we’ll take steps to implement it.

The body of the

  1. First, let’s design the basic framework of the library:
 const BaseStorage = function(preId, timeSign){
   // Initialize some operations
 }

 BaseStorage.prototype = {
   storage: localStorage || window.localStorage,
   set: function(key, value, cb, time){},get: function(key, cb){},// Delete the storage. If the storage is successfully deleted, the deleted content is returned
   remove: function(key, cb){}}Copy the code

As you can see, we have three core apis for storage: SET, GET, and Remove. We use localStorage as the base library to support this, but you can also replace it with sessionStorage or something else.

  1. With the basic skeleton in place, we can encapsulate the basic functionality by adding a property to the prototype that lists the states in the data operation.
status: {
 SUCCESS: 0./ / success
 FAILURE: 1./ / fail
 OVERFLOW: 2.// Data overflow
 TIMEOUT: 3  / / timeout
},
Copy the code

In order to achieve the expiration time, we have two kind of way of thinking, the first is to put an expiration time onto a storage, each operation check whether it is outdated, but the plan means to different keys to set different expiration time of storage and the matching, it will take up the extra memory, also not convenient to maintenance. Another method is to store the expiration time in the key value, separate the time and value by identifier, intercept the expiration time from the value each time, and then return the real value. This scheme does not add additional key-value pairs to store, and is relatively easy to maintain, so we use this scheme. To distinguish between different library objects, we can also add a key prefix like this:

const BaseLocalStorage = function(preId, timeSign){
   this.preId = preId; / / key prefix
   this.timeSign = timeSign || "| | -;  // The delimiter of expiration time and value
 }
Copy the code

Based on this idea, we can implement the following.

  • GetKey — A method that decorates a key without affecting the user’s influence on the real key
getKey: function(key){
     return this.preId + key
   },
Copy the code
  • Set to implement
set: function(key, value, cb, time){
     var status = this.status.SUCCESS,
     key = this.getKey(key);
     // Set the expiration time. If you do not set the expiration time, the default is one month
     try{
       time = new Date(time).getTime() || time.getTime();
     }catch(e){
       time = new Date().getTime() + 1000*60*60*24*31
     }
     try{
       this.storage.setItem(key, time + this.timeSign + value);
     }catch(e){
       status = this.status.OVERFLOW;
     }
     // Callback after the operation is complete
     cb && cb.call(this, status, key, value)
   }
Copy the code
  • Get to realize
get: function(key, cb){
     var status = this.status.SUCCESS,
     key = this.getKey(key),
     value = null,
     timeSignLen = this.timeSign.length,
     that = this,
     index,
     time,
     result;
     try{
       value = that.storage.getItem(key);
     }catch(e){
       result = {
         status: that.status.FAILURE,
         value: null
       }
       cb && cb.call(this, result.status, result.value);
       return result
     }
     if(value) {
       index = value.indexOf(that.timeSign);
       time = +value.slice(0, index);
       // Check whether it is expired. If it is expired, it will be cleared
       if(time > new Date().getTime() || time == 0){
         value = value.slice(index+timeSignLen);
       }else{
         value = null, status = that.status.TIMEOUT; that.remove(key); }}else{
       status = that.status.FAILURE;
     }
     result = {
       status: status,
       value: value
     };
     cb && cb.call(this, result.status, result.value);
     return result
   }
Copy the code
  • Remove implementation
// Delete the storage. If the storage is successfully deleted, the deleted content is returned
   remove: function(key, cb){
     var status = this.status.FAILURE,
     key = this.getKey(key),
     value = null;
     try{
       value = this.storage.getItem(key);
     }catch(e){
       // dosomething
     }
     if(value){
       try{
         this.storage.removeItem(key);
         status = this.status.SUCCESS;
       }catch(e){
         // dosomething
       }
     }
     cb && cb.call(this, status, status > 0 ? null : value.slice(value.indexOf(this.timeSign) + this.timeSign.length))
   }
Copy the code

In the process of API implementation, because some kind of misoperation is likely to cause a storage error, so it is recommended to use trycatch wrap, so as to avoid affecting the logic behind.

Then we can use it like this:

let a = new BaseStorage('_'.The '@');
a.set('name'.'123')
a.get('name') // {status: 0, value: "123"}
// Set the expiration time
a.set('name'.'123'.null.new Date().getTime() + 1000*60*60*24*31)
/ / remove
a.remove('name')
Copy the code

Complete source code

/** * Data manager */
(function(win){
  const BaseStorage = function(preId, timeSign){
    this.preId = preId;
    this.timeSign = timeSign || "| | -;
  }
 
  BaseStorage.prototype = {
    status: {
      SUCCESS: 0.FAILURE: 1.OVERFLOW: 2.TIMEOUT: 3
    },
    storage: localStorage || window.localStorage,
    getKey: function(key){
      return this.preId + key
    },
    set: function(key, value, cb, time){
      var status = this.status.SUCCESS,
      key = this.getKey(key);
      // Set the expiration time. If you do not set the expiration time, the default is one month
      try{
        time = new Date(time).getTime() || time.getTime();
      }catch(e){
        time = new Date().getTime() + 1000*60*60*24*31
      }
      try{
        this.storage.setItem(key, time + this.timeSign + value);
      }catch(e){
        status = this.status.OVERFLOW;
      }
      cb && cb.call(this, status, key, value)
    },
    get: function(key, cb){
      var status = this.status.SUCCESS,
      key = this.getKey(key),
      value = null,
      timeSignLen = this.timeSign.length,
      that = this,
      index,
      time,
      result;
      try{
        value = that.storage.getItem(key);
      }catch(e){
        result = {
          status: that.status.FAILURE,
          value: null
        }
        cb && cb.call(this, result.status, result.value);
        return result
      }
      if(value) {
        index = value.indexOf(that.timeSign);
        time = +value.slice(0, index);
        if(time > new Date().getTime() || time == 0){
          value = value.slice(index+timeSignLen);
        }else{
          value = null, status = that.status.TIMEOUT; that.remove(key); }}else{
        status = that.status.FAILURE;
      }
      result = {
        status: status,
        value: value
      };
      cb && cb.call(this, result.status, result.value);
      return result
    },
    // Delete the storage. If the storage is successfully deleted, the deleted content is returned
    remove: function(key, cb){
      var status = this.status.FAILURE,
      key = this.getKey(key),
      value = null;
      try{
        value = this.storage.getItem(key);
      }catch(e){
        // dosomething
      }
      if(value){
        try{
          this.storage.removeItem(key);
          status = this.status.SUCCESS;
        }catch(e){
          // dosomething
        }
      }
      cb && cb.call(this, status, status > 0 ? null : value.slice(value.indexOf(this.timeSign) + this.timeSign.length)) } } win.BS = BaseStorage; }) (window)
 
Copy the code

You can also expand more powerful functions based on this, if you have better ideas, welcome to exchange, discuss.

More recommended

  • How to use gulP4 development project scaffolding
  • How to write your own JS library in less than 200 lines of code
  • A summary of common JS functions that make you more productive in an instant
  • A picture shows you how to play vue-Cli3 quickly
  • 3 minutes teach you to use native JS implementation with progress listening file upload preview component
  • 3 minutes teach you to use native JS implementation with progress listening file upload preview component
  • Developing travel List with Angular8 and Baidu Maps API
  • Js basic search algorithm implementation and 1.7 million data under the performance test
  • How to make front-end code 60 times faster
  • Front End Algorithm series array deweighting
  • Vue Advanced Advanced series – Play with Vue and vuex in typescript
  • In the first three years, talk about the top five books worth reading