LRU简称最近最少使用算法,选择最近最久未使用的页面予以淘汰。

27 阅读1分钟
// 实现步骤
// 1. 用一个数组来存储数据
// 2. 数组的头部是最近使用的数据,尾部是最久未使用的数据
// 3. 当有新数据被访问时,从头部插入,如果数据已经存在,从原来的位置删除,插入到头部
// 4. 当数组长度超过最大值时,删除尾部数据
// 5. 当数据被访问时,将数据从原来的位置删除,插入到头部
// 6. 当数据被删除时,从数组中删除


/**
 * LRU简称最近最少使用算法,选择最近最久未使用的页面予以淘汰。
 * 
 * put:添加数据
 *    key:string
 *    value:any
 * 
 * update:更新数据
 *    key:string
 *    value:any
 * 
 * get:获取数据
 *    key:string
 * 
 * delete:删除数据
 *    key:string
 * 
 * getSize:获取空间容量
 * 
 * setSize:设置空间容量
 *    max:最大容量
 * 
 * getAll:获取空间所有数据
 * 
 * clear:清空所有数据
 * 
 * 配置项:
 * options:{ max:最大空间容量, local:本地缓存, session:会话缓存 }
 */
class LRU {
  constructor(options) {
    this.max = (options && options.max && options.max) || 10;
    this.localStorage = (options && options.local && options.local) || false;
    this.sessionStorage = (options && options.session && options.session) || false;
    this.chacheProxy = [];
    this.chache = [];
    this.subscrible = new Subscrible();
    if (this.localStorage || this.sessionStorage) this.storageKey = 'LRU_CACHE'

    if (this.localStorage) {
      this.subscrible.subscrible('put_l', (data) => {
        localStorage.setItem(this.storageKey, JSON.stringify(data))
      })
    }

    if (this.sessionStorage) {
      this.subscrible.subscrible('put_s', (data) => {
        sessionStorage.setItem(this.storageKey, JSON.stringify(data))
      })
    }
  }

  getStorage() {
    if (this.localStorage) {
      const str = localStorage.getItem(this.storageKey);
      if (str) {
        return JSON.parse(str);
      }
    }
    if (this.sessionStorage) {
      const str = sessionStorage.getItem(this.storageKey);
      if (str) {
        return JSON.parse(str);
      }
    }
  }

  _key(key) {
    if (typeof key !== 'string') {
      throw TypeError('key 必须是字符串')
    }
  }

  put(key, value) {
    this._key(key)
    const index = this.chache.findIndex(item => item.key === key)
    if (index > -1) {
      if (this.chache.length >= this.max) {
        this.chache = this.chache.slice(0, this.max);
      } else {
        this.chache.unshift(...this.chache.splice(index, 1))
      }
    } else {
      if (this.chache.length >= this.max) {
        this.chache.unshift({
          key,
          value
        });
        this.chache = this.chache.slice(0, this.max);
      } else {
        this.chache.unshift({
          key,
          value,
        })
      }
    }
    this.subscrible.publisher('put_l', this.chache);
    this.subscrible.publisher('put_s', this.chache);
  }

  update(key, value) {
    this._key(key);
    const index = this.chache.findIndex(item => {
      return item.key === key;
    })
    if (index > -1) {
      this.chache.splice(index, 1);
      this.chache.unshift({
        key,
        value
      })
    }
  }

  get(key) {
    this._key(key)
    const index = this.chache.findIndex(item => {
      return item.key === key;
    })
    if (index > -1) {
      const item = this.chache.splice(index, 1)[0];
      this.chache.unshift(item)
      return item;
    } else {
      return {
        msg: `当前key为:'${key}'的数据,不存在!!!`
      }
    }
  }

  delete(key) {
    this._key(key)
    const index = this.chache.findIndex(item => {
      return item.key === key;
    })
    if (index > -1) {
      this.chache.splice(index, 1);
    }
    this.subscrible.publisher('put_l', this.chache);
    this.subscrible.publisher('put_s', this.chache);
  }

  getSize() {
    return this.max;
  }

  setSize(max) {
    if (typeof max !== 'number') {
      throw TypeError('max 必须为数字类型');
    }
    if (max < 1) {
      throw RangeError('必须大于0')
    }
    this.max = max;
  }

  getAll() {
    return this.chache;
  }

  clear() {
    this.chache = [];
    this.subscrible.publisher('put_l', this.chache);
    this.subscrible.publisher('put_s', this.chache);
  }
}


class Subscrible {
  constructor() {
    this.events = {};
  }

  subscrible(event, cb) {
    if (!this.events[event]) {
      this.events[event] = cb;
    }
  }

  publisher(event, data) {
    if (this.events[event]) {
      this.events[event](data);
    }
  }
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>LRU</title>
</head>

<body>
  <script src="./index.js"></script>
  <script type="text/javascript">
    (function () {
      const lru = new LRU({
        local: false,
        session: false,
        max: 20
      });
      lru.put('spl1', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl2', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl3', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl4', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl5', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl6', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl7', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl8', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl9', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl10', { name: '阿森纳电磁阀1', age: 30, phone: '15233866823' })
      lru.put('spl11', { name: '阿森纳电磁阀1', age: 30, phone: '15233866883' })
      console.log('---------------')
      console.log(lru.getAll())
    })()
  </script>
</body>

</html>

image.png

image.png