Интервьюер: Как установить срок действия поддержки localStorage?

внешний интерфейс GitHub JavaScript
Интервьюер: Как установить срок действия поддержки localStorage?

говорить сlocalStorageПредположительно знакомые с фронтендом друзья не будут незнакомы, можем воспользоваться предоставленнымgetItem, setItem, removeItem, clearэти несколькоAPIЛегко «читать, писать, удалять» данные, хранящиеся локально в браузереоперации, но по сравнению сcookie, localStorageЕдинственная ложка дегтя это«Невозможно установить срок действия каждого ключа»**.

Свойство localStorage позволяет нам получить доступ к объекту Хранилище происхождения документа; сохраненные данные будут храниться в сеансе браузера. localStorage похож на sessionStorage, но разница в том, что данные, хранящиеся в localStorage, могут храниться длительное время, а при завершении сеанса страницы, то есть при закрытии страницы, данные, хранящиеся в sessionStorage, будут очищены.

Мы также должны отметить, чтоlocalStorageПары ключ-значение всегда хранятся в виде строк.

описание проблемы

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

1. Основное решение

Для друзей, которые только знакомятся с фронтендом, ответ можно дать сразу:

localStorage.setItem('dooring', '1.0.0')
// 设置一小时的有效期
const expire = 1000 * 60 * 60;
setTimeout(() => {
  localStorage.setItem('dooring', '')
}, expire)

Конечно, это решение может решить временную проблему, но если вы хотите установить срок действия любого ключа, вам нужно написать несколько таймеров для использования этого решения.«Стоимость обслуживания чрезвычайно высока, и это не способствует повторному использованию техники».

2. Промежуточный раствор

После того, как front-end инженеры имеют определенный опыт работы, они часто рассматривают вопросы проектирования и повторного использования, и имеют определенное понимание структуры данных, поэтому могут быть следующие решения:

  1. Используйте **"localStorage"**, чтобы сохранить таблицу сопоставления {key(key): expire(время истечения срока действия)}
  2. Перепишите **"localStorage API"**, дважды инкапсулируйте метод

Аналогичный код выглядит следующим образом:

const store = {
  // 存储过期时间映射
  setExpireMap: (key, expire) => {
    const expireMap = localStorage.getItem('EXPIRE_MAP') || "{}"
    localStorage.setItem(
      'EXPIRE_MAP', 
      JSON.stringify({
      ...JSON.parse(expireMap),
      key: expire
    }))
  },
  setItem: (key, value, expire) => {
    store.setExpireMap(key, expire)
    localStorage.setItem(key, value)
  },
  getItem: (key) => {
    // 在取值之前先判断是否过期
    const expireMap = JSON.parse(
      localStorage.getItem('EXPIRE_MAP') || "{}"
    )
    if(expireMap[key] && expireMap[key] < Date.now()) {
      return localStorage.getItem(key)
    }else {
      localStorage.removeItem(key)
      return null
    }
  }
  // ...
}

В мгновение ока это решение решает проблему повторного использования и может использоваться разными командами, но все же есть некоторые недостатки:

  • правильноstore2 копии данных должны поддерживаться во время работы и занимают место в кэше
  • еслиEXPIRE_MAPСлучайное удаление аннулирует все сроки действия
  • Отсутствие более гибкого управления процессом операции (такой как статус операции, обратный вызов операции и т.д.)

3. Передовые решения

Что мы должны сделать, чтобы снизить затраты на обслуживание и занимаемое пространство, а также обеспечить определенную степень гибкости управления и отказоустойчивости?

Здесь я думаю о двух похожих решениях:

  1. сохранить время истечения срока действия, чтобыkey, например dooring|6000, используйте разделитель "|" для разделения каждого значенияkeyа такжеexpireвывести, судить
  2. сохранить время истечения срока действия, чтобыvalue, например 1.0.0|6000, остальные такие же, как 1

Для большей инкапсуляции и надежности мы также можем настроить обратные вызовы в разных состояниях, которые просто реализованы следующим образом:

const store = {
  preId: 'xi-',
  timeSign: '|-door-|',
  status: {
    SUCCESS: 0,
    FAILURE: 1,
    OVERFLOW: 2,
    TIMEOUT: 3,
  },
  storage: localStorage || window.localStorage,
  getKey: function (key: string) {
    return this.preId + key;
  },
  set: function (
    key: string,
    value: string | number,
    time?: Date & number,
    cb?: (status: number, key: string, value: string | number) => void,
  ) {
    let _status = this.status.SUCCESS,
      _key = this.getKey(key),
      _time;
    // 设置失效时间,未设置时间默认为一个月
    try {
      _time = time
        ? new Date(time).getTime() || time.getTime()
        : new Date().getTime() + 1000 * 60 * 60 * 24 * 31;
    } 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: string,
    cb?: (status: number, value: string | number | null) => void,
  ) {
    let 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;
  },
  // ...
};

export default store;

Таким образом, мы достигли каждогоkeyКаждый из них имеет независимое время истечения срока действия и может легко контролировать статус различных результатов операции ~

4. Зольный раствор

Конечно, раствор золы использовать непосредственноxijsэтоjavascriptБиблиотека инструментов, поскольку я инкапсулировал приведенную выше полную схему реализации в эту библиотеку, нам нужно использовать только следующую схему, чтобы легко использовать мощные инструменты со сроком действия."локальное хранилище"метод:

//  先安装 yarn add xijs
import { store } from 'xijs';
// 设置带有过期时间的key
store.set('name', 'dooring', Date.now() + 1000);
console.log(store.get('name'));
setTimeout(() => {
  console.log(store.get('name'));
}, 1000);

// 设置成功后的回调
store.set('dooring', 'xuxiaoxi', Date.now() + 1000, (status, key, value) => {
  console.log('success');
});

в то же времяxijsМы продолжаем расширять полезные функции инструментов, чтобы сделать развитие бизнеса более эффективным.Мы интегрировали следующие функции инструментов:

  • "хранить"на основеlocalStorageБиблиотека инкапсулированного кэша верхнего уровня, которая поддерживает настройку времени истечения срока действия и поддерживает обратные вызовы операций.
  • "УУИД"Генерирует уникальный идентификатор, длина поддержки предоставлена
  • "randomStr"Генерировать указанное количество случайных строк
  • "форматДата"Готовые инструменты форматирования времени
  • "развенчать"Функция защиты от сотрясений
  • "Дроссель"Функция дроссельной заслонки
  • "url2obj"Преобразование строки URL в объект
  • "obj2url"Преобразование объекта в закодированную строку URL
  • "исПК"Определите, является ли устройство типом ПК

адрес гитхаба:GitHub.com/Mr X U соус/Маленький…

Адрес документа:h5.dooring.cn/xijs

Если вы найдете это полезным, не забудьте поставить звездочку~

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