Home  >  Article  >  Web Front-end  >  Detailed explanation of steps to implement caching algorithm in JS

Detailed explanation of steps to implement caching algorithm in JS

php中世界最好的语言
php中世界最好的语言Original
2018-05-04 09:04:371580browse

This time I will bring you a detailed explanation of the steps to implement the caching algorithm in JS. What are the precautions for implementing the caching algorithm in JS. The following is a practical case, let's take a look.

FIFO

The simplest caching algorithm is to set the cache upper limit. When the cache upper limit is reached, it will be eliminated according to the first-in, first-out strategy, and then added Enter new k-v.

Using an object as a cache, an array matches the order in which records are added to the object to determine whether the upper limit is reached. If the upper limit is reached, take the first element key in the array, corresponding to Delete the key value in the object.

/**
 * FIFO队列算法实现缓存
 * 需要一个对象和一个数组作为辅助
 * 数组记录进入顺序
 */
class FifoCache{
  constructor(limit){
    this.limit = limit || 10
    this.map = {}
    this.keys = []
  }
  set(key,value){
    let map = this.map
    let keys = this.keys
    if (!Object.prototype.hasOwnProperty.call(map,key)) {
      if (keys.length === this.limit) {
        delete map[keys.shift()]//先进先出,删除队列第一个元素
      }
      keys.push(key)
    }
    map[key] = value//无论存在与否都对map中的key赋值
  }
  get(key){
    return this.map[key]
  }
}
module.exports = FifoCache

LRU

LRU (Least recently used, least recently used) algorithm. The point of view of this algorithm is that the data that has been accessed recently has a greater probability of being accessed in the future. When the cache is full, the least interested data will be eliminated first.

Algorithm implementation idea: Based on the data structure of a double linked list, when it is not full, the new k-v is placed at the head of the linked list, and the k-v is moved every time the k-v in the cache is obtained. When the cache is full, the ones at the end will be eliminated first.

The characteristics of a doubly linked list are head and tail pointers. Each node has prev (predecessor) and next (successor) pointers pointing to its previous and next nodes respectively.

Key point: Pay attention to the order issue during the insertion process of the double linked list. The pointer must be processed first while keeping the linked list continuous, and finally the original pointer points to the newly inserted element. In the implementation of the code Please pay attention to the order I explained in Notes!

class LruCache {
  constructor(limit) {
    this.limit = limit || 10
    //head 指针指向表头元素,即为最常用的元素
    this.head = this.tail = undefined
    this.map = {}
    this.size = 0
  }
  get(key, IfreturnNode) {
    let node = this.map[key]
    // 如果查找不到含有`key`这个属性的缓存对象
    if (node === undefined) return
    // 如果查找到的缓存对象已经是 tail (最近使用过的)
    if (node === this.head) { //判断该节点是不是是第一个节点
      // 是的话,皆大欢喜,不用移动元素,直接返回
      return returnnode ?
        node :
        node.value
    }
    // 不是头结点,铁定要移动元素了
    if (node.prev) { //首先要判断该节点是不是有前驱
      if (node === this.tail) { //有前驱,若是尾节点的话多一步,让尾指针指向当前节点的前驱
        this.tail = node.prev
      }
      //把当前节点的后继交接给当前节点的前驱去指向。
      node.prev.next = node.next
    }
    if (node.next) { //判断该节点是不是有后继
      //有后继的话直接让后继的前驱指向当前节点的前驱
      node.next.prev = node.prev
      //整个一个过程就是把当前节点拿出来,并且保证链表不断,下面开始移动当前节点了
    }
    node.prev = undefined //移动到最前面,所以没了前驱
    node.next = this.head //注意!!! 这里要先把之前的排头给接到手!!!!让当前节点的后继指向原排头
    if (this.head) {
      this.head.prev = node //让之前的排头的前驱指向现在的节点
    }
    this.head = node //完成了交接,才能执行此步!不然就找不到之前的排头啦!
    return IfreturnNode ?
      node :
      node.value
  }
  set(key, value) {
    // 之前的算法可以直接存k-v但是现在要把简单的 k-v 封装成一个满足双链表的节点
    //1.查看是否已经有了该节点
    let node = this.get(key, true)
    if (!node) {
      if (this.size === this.limit) { //判断缓存是否达到上限
        //达到了,要删最后一个节点了。
        if (this.tail) {
          this.tail = this.tail.prev
          this.tail.prev.next = undefined
          //平滑断链之后,销毁当前节点
          this.tail.prev = this.tail.next = undefined
          this.map[this.tail.key] = undefined
          //当前缓存内存释放一个槽位
          this.size--
        }
        node = {
          key: key
        }
        this.map[key] = node
        if(this.head){//判断缓存里面是不是有节点
          this.head.prev = node
          node.next = this.head
        }else{
          //缓存里没有值,皆大欢喜,直接让head指向新节点就行了
          this.head = node
          this.tail = node
        }
        this.size++//减少一个缓存槽位
      }
    }
    //节点存不存在都要给他重新赋值啊
    node.value = value
  }
}
module.exports = LruCache

The specific idea is that if the node you want to get is not the head node (that is, it is already the most recently used node, and there is no need to move the node position), you must first perform a smooth link breaking operation and handle the pointer pointed to. Relationship, take out the node that needs to be moved to the front, and perform the insertion operation into the linked list.

I believe you have mastered the method after reading the case in this article. For more exciting information, please pay attention to other related articles on the php Chinese website!

Recommended reading:

How to implement dynamic parameter passing of query in vue-router

Why can’t you use IP to access webpack locally? Development environment

The above is the detailed content of Detailed explanation of steps to implement caching algorithm in JS. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn