欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用JavaScript實(shí)現(xiàn)LRU緩存的代碼詳解

 更新時(shí)間:2024年05月21日 11:20:31   作者:隱藏用戶_y  
LRU(Least?Recently?Used)算法是一種廣泛應(yīng)用于內(nèi)存管理和緩存系統(tǒng)的策略,本文將介紹LRU算法的基本原理,并通過(guò)JavaScript實(shí)現(xiàn)案例,幫助讀者理解其在前端開(kāi)發(fā)中的應(yīng)用場(chǎng)景,需要的朋友可以參考下

引言

LRU(Least Recently Used)算法是一種廣泛應(yīng)用于內(nèi)存管理和緩存系統(tǒng)的策略,在微前端、狀態(tài)管理以及性能優(yōu)化等場(chǎng)景下,合理使用緩存機(jī)制能夠有效提升應(yīng)用性能。本文將介紹LRU算法的基本原理,并通過(guò)JavaScript實(shí)現(xiàn)案例,幫助讀者理解其在前端開(kāi)發(fā)中的應(yīng)用場(chǎng)景。

LRU算法原理

LRU(最近最少使用)算法是一種常用的緩存淘汰策略,它假定“最近最久未使用的數(shù)據(jù)在未來(lái)被訪問(wèn)的可能性最小”。當(dāng)緩存空間不足時(shí),LRU會(huì)優(yōu)先移除最近最少使用的數(shù)據(jù),為新數(shù)據(jù)騰出存儲(chǔ)空間。

實(shí)現(xiàn)方式

哈希表適合快速查找、插入和刪除的場(chǎng)景,而雙向鏈表適合頻繁插入和刪除節(jié)點(diǎn)的場(chǎng)景。在某些情況下,這兩種數(shù)據(jù)結(jié)構(gòu)也可以結(jié)合實(shí)現(xiàn)LRU緩存算法時(shí),可以使用哈希表存儲(chǔ) key 和對(duì)應(yīng)的節(jié)點(diǎn),雙向鏈表存儲(chǔ)實(shí)際的數(shù)據(jù)節(jié)點(diǎn),以實(shí)現(xiàn)快速的查找和插入刪除操作。

圖解示例

假設(shè)設(shè)計(jì)一個(gè)容量為3的LRU緩存

首先添加3個(gè)元素

哈希表中依次添加數(shù)據(jù)的key值:key1,key2,key3

雙向鏈表存儲(chǔ)哈希對(duì)(key,value),key3是最后一個(gè)添加的(最新添加記錄是key3),那么key3對(duì)應(yīng)的哈希值添加到鏈表的頭部node3。表示最近使用的。

這個(gè)時(shí)候如果要添加第四個(gè)數(shù)據(jù),key4放入哈希表,node4放入雙向鏈表頭部,node4包含key4,value4,然而此時(shí)容量不足,需要?jiǎng)h除一個(gè)元素,從尾部刪除一個(gè)最久沒(méi)使用的元素,刪除上面圖示中的node1的數(shù)據(jù),同時(shí)在哈希表中刪除node1對(duì)應(yīng)的key1 把node4添加到鏈表頭部,key4添加進(jìn)哈希表是同步進(jìn)行的。

如果最近要訪問(wèn)key3,需要把node3從當(dāng)前位置刪除,并插入到鏈表頭部

簡(jiǎn)而言之:

每次添加元素到鏈表中的時(shí)候都是從頭部添加

每次刪除元素的時(shí)候都是從尾部刪除

刪除的時(shí)候同時(shí)從哈希表里面刪除對(duì)應(yīng)的key

再次訪問(wèn)的元素,需要把元素移動(dòng)到鏈表的頭部

實(shí)現(xiàn)代碼

使用哈希鏈表,可以在每個(gè)緩存項(xiàng)的節(jié)點(diǎn)上同時(shí)存儲(chǔ)鍵值信息以及指向鏈表中前后節(jié)點(diǎn)的引用。當(dāng)一個(gè)緩存項(xiàng)被訪問(wèn)時(shí),先通過(guò)哈希表找到對(duì)應(yīng)節(jié)點(diǎn),然后將其從原有位置移出并插入鏈表尾部

class LRUCacheNode {
  constructor(key, value) {
    this.key = key;
    this.value = value;
    this.prev = null;
    this.next = null;
  }
}


class LRUCache {
  constructor(capacity = 500) {
    this.capacity = capacity;
    this.cacheMap = new Map(); // 使用哈希表存儲(chǔ)鍵值對(duì)
    this.doubleLinkedList = new DoublyLinkedList(); // 雙向鏈表維護(hù)緩存順序
  }

  get(key) {
    if (this.cacheMap.has(key)) {
      const node = this.cacheMap.get(key);
      this.doubleLinkedList.moveToTail(node); // 將節(jié)點(diǎn)移動(dòng)到鏈表尾部,表示最新訪問(wèn)
      return node.value;
    }
    return -1; // 或者返回null,表示key不存在于緩存中
  }

  put(key, value) {
    if (this.cacheMap.has(key)) {
      const node = this.cacheMap.get(key);
      node.value = value;
      this.doubleLinkedList.moveToTail(node);
    } else {
      if (this.cacheMap.size >= this.capacity) {
        const headNode = this.doubleLinkedList.deleteHead();
        this.cacheMap.delete(headNode.key); // 移除最舊的緩存項(xiàng)
      }
      const newNode = new Node(key, value);
      this.cacheMap.set(key, newNode);
      this.doubleLinkedList.addToTail(newNode);
    }
  }
}

// 雙向鏈表類和節(jié)點(diǎn)類的實(shí)現(xiàn)略(根據(jù)實(shí)際需求實(shí)現(xiàn))
class Node {
  constructor(key, value) {
    this.key = key; // 節(jié)點(diǎn)鍵值
    this.value = value; // 節(jié)點(diǎn)數(shù)據(jù)值
    this.prev = null; // 前驅(qū)節(jié)點(diǎn)引用
    this.next = null; // 后繼節(jié)點(diǎn)引用
  }
}
class DoublyLinkedList {
  constructor() {
    this.head = null; // 頭節(jié)點(diǎn)
    this.tail = null; // 尾節(jié)點(diǎn)
  }

  /**
   * 添加節(jié)點(diǎn)到鏈表尾部
   * @param {Node} newNode 新節(jié)點(diǎn)
   */
  addToTail(newNode) {
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      newNode.prev = this.tail;
      this.tail.next = newNode;
      this.tail = newNode;
    }
  }

  /**
   * 移除頭節(jié)點(diǎn)并返回
   * @returns {Node | null} 刪除的頭節(jié)點(diǎn)或null(如果鏈表為空)
   */
  deleteHead() {
    if (!this.head) return null;

    const deletedNode = this.head;
    this.head = this.head.next;

    if (this.head) {
      this.head.prev = null;
    } else {
      this.tail = null;
    }

    return deletedNode;
  }

  /**
   * 將指定節(jié)點(diǎn)移動(dòng)到鏈表尾部
   * @param {Node} node 需要移動(dòng)的節(jié)點(diǎn)
   */
  moveToTail(node) {
    if (node === this.tail) return; // 如果已經(jīng)是尾節(jié)點(diǎn),則無(wú)需移動(dòng)

    // 斷開(kāi)當(dāng)前節(jié)點(diǎn)與前后節(jié)點(diǎn)的連接
    node.prev.next = node.next;
    if (node.next) node.next.prev = node.prev;

    // 將節(jié)點(diǎn)添加至鏈表尾部
    this.addToTail(node);
  }
  
  // 其他可能的方法,如查找節(jié)點(diǎn)、在指定位置插入節(jié)點(diǎn)等...
}


使用場(chǎng)景

路由緩存

Vue.js 中的 keep-alive 組件雖然并未直接采用LRU算法,但在實(shí)際項(xiàng)目中,我們可以基于LRU策略自定義實(shí)現(xiàn)路由組件的緩存功能。

資源加載

對(duì)于頻繁請(qǐng)求且響應(yīng)較慢的API,可以通過(guò)LRU緩存最近請(qǐng)求的結(jié)果,減少網(wǎng)絡(luò)請(qǐng)求次數(shù)。

狀態(tài)管理

在Vuex或Redux等狀態(tài)管理庫(kù)中,也可以利用LRU算法進(jìn)行緩存,避免頻繁計(jì)算或獲取昂貴的狀態(tài)。

業(yè)務(wù)場(chǎng)景

電商大促,瀏覽器瀏覽歷史,微博熱點(diǎn)。實(shí)現(xiàn)的具體可能不同,但是思路均可使用LRU緩存實(shí)現(xiàn).

網(wǎng)頁(yè)瀏覽歷史

實(shí)現(xiàn)一個(gè)簡(jiǎn)單的瀏覽歷史記錄功能

class LRUCache {
    constructor(capacity) {
        this.capacity = capacity;
        this.cache = new Map();
    }

    get(key) {
        if (this.cache.has(key)) {
            const value = this.cache.get(key);
            // 刪除舊數(shù)據(jù)再重新插入,以更新最近訪問(wèn)的順序
            this.cache.delete(key);
            this.cache.set(key, value);
            return value;
        }
        return null;
    }

    put(key, value) {
        if (this.cache.has(key)) {
            this.cache.delete(key);
        } else if (this.cache.size >= this.capacity) {
            // 超出容量時(shí)刪除最久未訪問(wèn)的數(shù)據(jù)(即最近使用頻率最低的數(shù)據(jù))
            const keys = this.cache.keys();
            this.cache.delete(keys.next().value);
        }
        this.cache.set(key, value);
    }

    displayHistory() {
        console.log("Browser History:");
        for (let [key, value] of this.cache) {
            console.log(key + " -> " + value);
        }
    }
}

// 使用示例
const historyCache = new LRUCache(5); // 設(shè)置緩存容量為5

historyCache.put("Page 1", "www.page1.com");
historyCache.put("Page 2", "www.page2.com");
historyCache.put("Page 3", "www.page3.com");
historyCache.get("Page 1");

// 輸出瀏覽歷史記錄
historyCache.displayHistory();

在上面的示例中,LRUCache 類實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的 LRU 緩存,通過(guò) get 方法獲取歷史記錄,并通過(guò) put 方法添加歷史記錄。displayHistory 方法用于展示瀏覽歷史記錄。

可以根據(jù)實(shí)際需求進(jìn)一步擴(kuò)展和優(yōu)化這個(gè)示例,比如添加時(shí)間戳來(lái)記錄訪問(wèn)時(shí)間、持久化歷史記錄到本地存儲(chǔ)等功能。希望這個(gè)示例能幫助你實(shí)現(xiàn)瀏覽歷史記錄功能。

以上就是使用JavaScript實(shí)現(xiàn)LRU緩存的代碼詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript LRU緩存的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • .net MVC+Bootstrap下使用localResizeIMG上傳圖片

    .net MVC+Bootstrap下使用localResizeIMG上傳圖片

    這篇文章主要為大家詳細(xì)介紹了.net MVC和Bootstrap下使用 localResizeIMG上傳圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • JavaScript練習(xí)小項(xiàng)目之修改div塊的顏色

    JavaScript練習(xí)小項(xiàng)目之修改div塊的顏色

    這篇文章主要給大家介紹了關(guān)于JavaScript練習(xí)小項(xiàng)目之修改div塊的顏色的相關(guān)資料,文中通過(guò)舉例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-01-01
  • JavaScript 亂碼問(wèn)題

    JavaScript 亂碼問(wèn)題

    在用js寫網(wǎng)頁(yè)時(shí),如果html等內(nèi)容全部用document.write輸出,包括<html>、<meta等標(biāo)簽,當(dāng)嵌套時(shí),會(huì)出現(xiàn)輸出內(nèi)容為亂碼的問(wèn)題
    2009-08-08
  • js Canvas繪制圓形時(shí)鐘效果

    js Canvas繪制圓形時(shí)鐘效果

    這篇文章主要為大家詳細(xì)介紹了js Canvas繪制圓形時(shí)鐘效果的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • 多種方式實(shí)現(xiàn)js圖片預(yù)覽

    多種方式實(shí)現(xiàn)js圖片預(yù)覽

    這篇文章主要為大家詳細(xì)介紹了多種方式實(shí)現(xiàn)js圖片預(yù)覽,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 收藏一個(gè)代碼

    收藏一個(gè)代碼

    收藏一個(gè)代碼...
    2006-08-08
  • 微信小程序?qū)崿F(xiàn)性別單選效果

    微信小程序?qū)崿F(xiàn)性別單選效果

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)性別單選效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • JS新標(biāo)簽頁(yè)打開(kāi)的方法大全(讓你的網(wǎng)站訪問(wèn)更加便捷)

    JS新標(biāo)簽頁(yè)打開(kāi)的方法大全(讓你的網(wǎng)站訪問(wèn)更加便捷)

    在開(kāi)發(fā)Web應(yīng)用中我們常常需要在當(dāng)前頁(yè)面打開(kāi)一個(gè)鏈接,但又不希望離開(kāi)當(dāng)前頁(yè)面,這篇文章主要給大家介紹了關(guān)于JS新標(biāo)簽頁(yè)打開(kāi)的方法大全,通過(guò)這些方法可以讓你的網(wǎng)站訪問(wèn)更加便捷,需要的朋友可以參考下
    2023-10-10
  • JavaScript知識(shí)點(diǎn)整理

    JavaScript知識(shí)點(diǎn)整理

    本文是腳本之家小編日常整理的關(guān)于javascript知識(shí)點(diǎn),包括javascript擁有的特點(diǎn),組成部分,數(shù)據(jù)類型等方面,對(duì)javascript知識(shí)點(diǎn)相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧
    2015-12-12
  • js獲得當(dāng)前時(shí)區(qū)夏令時(shí)發(fā)生和終止的時(shí)間代碼

    js獲得當(dāng)前時(shí)區(qū)夏令時(shí)發(fā)生和終止的時(shí)間代碼

    這篇文章主要介紹了js獲得當(dāng)前時(shí)區(qū)夏令時(shí)發(fā)生和終止的時(shí)間代碼,需要的朋友可以參考下
    2014-02-02

最新評(píng)論