Реализовать библиотеку DAO со сроком действия на основе localStorage.

JavaScript Открытый исходный код

В этой статье в основном решается проблема, что родной localStorage не может устанавливать время истечения, и реализуется удобная и мощная библиотека localStorage через инкапсуляцию.О некоторых основных идеях и режимах инкапсуляции библиотек я воспользуюсь ранее написаннымКак написать собственную js-библиотеку менее чем за 200 строк кодаПодобным образом заинтересованные друзья могут учиться и общаться.

Идеи дизайна

Мы будем расширять на основе исходного API localStorage, чтобы поддерживать время истечения срока действия и обратный вызов после завершения операции. В конце статьи я приведу код завершения библиотеки, а дальше будем поэтапно его реализовывать.

текст

  1. Во-первых, давайте спроектируем базовую структуру библиотеки:
 const BaseStorage = function(preId, timeSign){
   // 初始化一些操作
 }

 BaseStorage.prototype = {
   storage: localStorage || window.localStorage,
   set: function(key, value, cb, time){
     
   },
   get: function(key, cb){
     
   },
   // 删除storage,如果删除成功,返回删除的内容
   remove: function(key, cb){
    
   }
 }

Как вы можете видеть выше, наше хранилище будет иметь три основных API, а именно установить, получить и удалить.Мы используем localStorage в качестве поддержки базовой библиотеки.Конечно, вы также можете заменить указанную выше библиотеку на sessionStorage или другие.

  1. С помощью базового скелета мы можем реализовать инкапсуляцию основных функций.Здесь мы сначала добавляем атрибут к прототипу, чтобы перечислить различные состояния в операции с данными.
status: {
 SUCCESS: 0, // 成功
 FAILURE: 1, // 失败
 OVERFLOW: 2, // 数据溢出
 TIMEOUT: 3  // 超时
},

Для того, чтобы реализовать время истечения, у нас есть две идеи.Первый заключается в том, чтобы сначала хранить время истечения в хранилище и проверять, истекло ли оно для каждой операции, но эта схема означает, что для разных ключей должны быть установлены разные сроки действия. Ей соответствует хранение времени, которое займет дополнительную библиотечную память и неудобно в обслуживании. Другой метод заключается в том, чтобы хранить время истечения в значении ключа, разделять время и значение по идентификатору, перехватывать время истечения из значения каждый раз, когда оно извлекается, а затем извлекать реальное значение и возвращать его.Эта схема не будет добавить Дополнительное хранилище пар ключ-значение относительно просто поддерживать, поэтому мы принимаем эту схему. Чтобы различать разные объекты библиотеки, мы также можем добавить префиксы ключей следующим образом:

const BaseLocalStorage = function(preId, timeSign){
   this.preId = preId; // 键前缀
   this.timeSign = timeSign || '|-|';  // 过期时间和值的分隔符
 }

Основываясь на этой идее, мы можем реализовать следующий шаг.

  • Getkee - метод модификации ключа, он не влияет на влияние пользователя на реальный ключ
getKey: function(key){
     return this.preId + key
   },
  • установить реализацию
set: function(key, value, cb, time){
     var status = this.status.SUCCESS,
     key = this.getKey(key);
     // 设置失效时间,未设置时间默认为一个月
     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
   }
  • удалить реализацию
// 删除storage,如果删除成功,返回删除的内容
   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))
   }

В процессе реализации API, из-за какой-то неправильной работы, очень вероятно, что хранилище сообщит об ошибке, поэтому рекомендуется обернуть его с помощью trycatch, чтобы не влиять на последующую логику.

Далее мы можем использовать его следующим образом:

let a = new BaseStorage('_', '@');
a.set('name', '123')
a.get('name') // {status: 0, value: "123"}
// 设置失效时间
a.set('name', '123', null, new Date().getTime() + 1000*60*60*24*31)
// 移除
a.remove('name')

Полный исходный код

/**
 * 数据管理器
 */
(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);
      // 设置失效时间,未设置时间默认为一个月
      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
    },
    // 删除storage,如果删除成功,返回删除的内容
    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)
 

Вы также можете расширить более мощные функции на основе этого.Если у вас есть идеи получше, добро пожаловать на обмен и обсуждение.

больше рекомендаций