Vue的缓存算法—LRU算法

赖尚荣
• 阅读 6214

最近在看Vue的源码,不得不说的是,Vue的源码十分优雅简洁,下面就来分享下Vue的缓存利用的算法LRU算法。

LRU算法

LRU是Least recently used的简写,主要原理是根据历史访问记录来淘汰数据,说白了就是这个算法认为如果数据被访问过,那么将来被访问的几率也高。其存储结构是一个双链表,最近被访问到的放在双链表的尾部,头部放的就是最早被访问到数据。关于算法的具体流程,可以来看下这个,这个可视化过程,模拟了lru算法进行调度的过程。

缺页数

lru在笔试题中也会经常出现,经常会考到的那就是缺页数,例如页面访问序列为:2,3,2,1,5,2,4,5,3,2,5,2, 分配给某个进程3页内存,求其缺页次数。
缺页数可以理解为,内存不满的次数,转到lru来看就是链表中有空节点的次数。下面来走一下整个流程(左为head右为tail):

  1. 2            // 第一次缺页

  2. 2 -> 3    // 第二次缺页

  3. 3 -> 2    // 第三次缺页

  4. 3 -> 2 -> 1

  5. 2 -> 1   // 第四次缺页

  6. 2 -> 1 -> 5

  7. 1 -> 5 -> 2

  8. 5 -> 2   // 第五次缺页

  9. 5 -> 2 -> 4

  10. 2 -> 4 -> 5

  11. 4 -> 5   // 第六次缺页

  12. 4 -> 5 -> 3

  13. 5 -> 3    // 第七次缺页

  14. 5 -> 3 -> 2

  15. 3 -> 2 -> 5

  16. 3 -> 5 -> 2

所以总共有着7次缺页,上面的这个流程也是算法的具体执行流程,可以看出的是当有新的节点进入时,首先会检测内存是否已满,如果满了的话,就先将头给移除,再在尾部添加上这个新节点;假若该节点在链表中存在,那么直接将这个节点拿到头部。下面来看下Vue对这个算法的实现:

vue中的lru

源码时src/cache.js,先来看看其构造函数:

// limit是最大容量
function Cache (limit) {
    this.size = 0;
    this.limit = limit;
    this.head = this.tail = undefined;
    this._keymap = Object.create(null);
}

尤大利用集合_keymap来存储已有的节点,在判断是否存在时,直接读取属性就行,不用在遍历一遍链表,这样降低了在查找过程中的时间复杂度。head代表着头节点,tail代表着尾节点,链表中的节点是这样的:

node {
    value: 键值,
    key: 键名,
    older: 指向前一个节点,head的older指向undefined,
    newer: 指向下一个节点,tail的newer指向undefined
}

来看get方法:

Cache.prototype.get = function (key, returnEntry) {
     var entry = this._keymap[key];
     // 本身没有,则不用调度,直接将新的节点插入到尾部即可
    if (entry === undefined) return;
    // 访问的就是尾部节点,则不需要调度    
    if (entry === this.tail) {
        return returnEntry ? entry : entry.value;
    }
    // 访问的不是尾部节点,需要将被访问节点拿到头部
    if (entry.newer) {
        if (entry === this.head) {
            this.head = entry.newer;
        }
        entry.newer.older = entry.older;
    }
    if (entry.older) {
        entry.older.newer = entry.newer;
    }
    entry.newer = undefined;
    entry.older = this.tail;
    if (this.tail) {
        this.tail.newer = entry;
    }
    this.tail = entry;
    return returnEntry ? entry : entry.value;
 };

get是为了得到链表中是否含有这个节点,假如有这个节点,那么还要对这个节点进行调度,也就是将节点拿到尾部。

// 将链表的头给去除
Cache.prototype.shift = function () {
    var entry = this.head;
    if (entry) {
        this.head = this.head.newer;
        this.head.older = undefined;
        entry.newer = entry.older = undefined;
        this._keymap[entry.key] = undefined;
        this.size--;
    }
    return entry;
};
p.put = function (key, value) {
    var removed;
    var entry = this.get(key, true);
    // 插入的情况,插入到尾部
    if (!entry) {
        // 如果集合已经满了,移除一个,并将其return
        if (this.size === this.limit) {
            removed = this.shift();
        }
        entry = {
            key: key
        };
        this._keymap[key] = entry;
        if (this.tail) {
            this.tail.newer = entry;
            entry.older = this.tail;
        } else {  // 链表中插入第一个节点时,头节点就是尾几点
            this.head = entry;
        }
        this.tail = entry;   // 节点会添加或者拿到尾部
        this.size++;
    }
    // 更新节点的value,假若本身链表中有,get方法中已经调度好,只要更新值就好
    entry.value = value;
    return removed;
};

至此,vue的cache代码已经全部解析完,其具体的作用由于源码刚刚开始读吗,目前还不清楚,不过应该在解析指令等方面有着重大的作用。

最后希望大家关注下算法演示

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Easter79 Easter79
4年前
Vue diff 算法
一、虚拟DOM(virtualdom)  diff算法首先要明确一个概念就是diff的对象是虚拟DOM(virtualdom),更新真实DOM是diff算法的结果。  注:virtualdom 可以看作是一个使用JavaScript模拟了DOM结构的树形结构,这个树结构包含
一起跳舞吧 一起跳舞吧
5年前
node.js操作Cookie
通过node.js建立了一个完整的网站不是一件容易的事,这涉及读取页面模板,从数据库中抽出数据构建成新的页面返回给客户端。但光是这样还不行,我们还要设置首部,在chrome中如果CSS没有设置正确的ContentType,会不起作用的。此处理还要考虑访问量,要设置缓存,缓存不单单是把东西从内存中读入读出就行,这样会撑爆电脑内存的,这用LRU算法(最近最少用
九路 九路
5年前
6 手写Java LinkedHashMap 核心源码
概述LinkedHashMap是Java中常用的数据结构之一,安卓中的LruCache缓存,底层使用的就是LinkedHashMap,LRU(LeastRecentlyUsed)算法,即最近最少使用算法,核心思想就是当缓存满时,会优先淘汰那些近期最少使用的缓存对象LruCache的缓存算法LruCache采用的缓存算法为LRU(LeastRe
小恐龙 小恐龙
5年前
LRU算法四种实现方式介绍
LRU全称是Least RecentlyUsed,即最近最久未使用的意思。LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
Wesley13 Wesley13
4年前
Java集合,ConcurrentHashMap底层实现和原理(常用于并发编程)
概述ConcurrentHashMap常用于并发编程,这里就从源码上来分析一下ConcurrentHashMap数据结构和底层原理。在开始之前先介绍一个算法,这个算法和Concurrent的实现是分不开的。CAS算法:CAS是英文单词CompareAndSwap的缩写,翻译过来就是比较并替换。CAS机制当中使用
Stella981 Stella981
4年前
Redis的过期策略和内存淘汰策略及LRU算法详解
全是干货的技术号:本文已收录在github,欢迎star/fork:https://github.com/Wasabi1234/JavaInterviewTutorial(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2FWasabi1234%2FJ
Stella981 Stella981
4年前
Redis5.0之后的内存策略
前言:这八种算法是基于redis5.0版之后的,他新增了新增allkeyslfu,volatilelfu这两种算法,也就是多了LFU算法,而LFU与LRU算法不同在于;LRU是淘汰最近最长时间未使用的页面进行淘汰,而LFU是要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。但是有些页在开始时使用次数很多,但以后就不再使用,
Stella981 Stella981
4年前
Redis做LRU缓存
当Redis用作缓存时,通常可以让它在添加新数据时自动逐出旧数据。这种行为在开发人员社区中非常有名,因为它是流行的memcached系统的默认行为。LRU实际上只是支持的驱逐方法之一。本页介绍了Redismaxmemory指令的更一般主题,该指令用于将内存使用限制为固定数量,并且它还深入介绍了Redis使用的LRU算法,实际上是精确LRU的近似值。
拆解雪花算法生成规则 | 京东物流技术团队
雪花算法(Snowflake)是一种生成分布式全局唯一ID的算法,生成的ID称为SnowflakeIDs或snowflakes。这种算法由Twitter创建,并用于推文的ID。目前仓储平台生成ID是用的雪花算法修改后的版本。