【前端方案】-表格排序列LRU快取方案

2023-06-07 18:00:26

目標:
排序後的表格列,頁面重新整理或者使用者重新登入後,能夠保持之前的操作排序

完成效果:

解決方案:
利用localstorage對排序後的表格列屬性進行儲存,頁面重新整理或者使用者重新進入該頁面時都先從localstorage中讀取
1.儲存方式:localstorage(key,value)
key - 表格增加設定屬性tableHeaderKey,以當前路由的path+tableHeaderKey來做key
value - 排序後的屬性列陣列(defaultKeys-所有屬性列key,selectedKeys要顯示的key,tableSize表格高度)只存key,減少儲存空間
2.儲存時機:
設定有tableHeaderKey並且showTableSetting開啟,進入頁面就讀取,沒有則先存一份
3.移除或新增列的情況:
(1)在後續需求迭代中,以前表格的欄位列可能會增加或者減少,需要將新的欄位列和localstorage中的舊有欄位列進行diff,如果存在刪除的欄位,則移除,存在新增欄位則自動追加。
(2)或者強制更新,通過讀取發版的版本號,如果發版的版本號大於舊的版本號,則清空localstorage。
升級方案:
針對localstorage快取太多的情況,會採用LRU演演算法對快取進行優化。
LRU全稱為Least Recently Used,即最近使用的。針對的是在有限的記憶體空間內,只快取最近使用的資料(即get和set的資料),超過有限記憶體空間的資料將會被刪除。
大致思路:

簡單實現思路

class LRUCache {
    data = new Map(); // 資料map
    constructor(length) {
    if (length < 1) throw new Error('長度不能小於1')
        this.length = length
    }

    set(key, value) {
        const data = this.data;
        // 如果存在該物件,則直接刪除
        if (data.has(key)) {
            data.delete(key);
        }
        // 將資料物件新增到map中
        data.set(key, value);
        if (data.size > this.length) {
            // 如果map長度超過最大值,則取出map中的第一個元素,然後刪除
            const delKey = data.keys().next().value
            data.delete(delKey);
        }
    }
    get(key) {
        const data = this.data;
        // 資料map中沒有key對應的資料,則返回null
        if (!data.has(key)) return null;
        const value = data.get(key);
        // 返回資料前,先刪除原資料,然後在新增,就可以保持在最新
        data.delete(key);
        data.set(key, value);
        return value;
    }
}

const lruCache = new LRUCache(2);
lruCache.set('1', 1); // Map(1) {1 => 1}
lruCache.set('2',2); // Map(2) {1 => 1, 2 => 2}
console.log(lruCache.get('1')); // Map(2) {2 => 2, 1 => 1}
lruCache.set('3',3); // Map(2) {1 => 1, 3 => 3}
console.log(lruCache.get('2')); // null
lruCache.set('4',4); // Map(2) {3 => 3, 4 => 4}
console.log(lruCache.get('1')); // null
console.log(lruCache.get('3')); // Map(2) {4 => 4, 3 => 3}
console.log(lruCache.get('4')); // Map(2) {3 => 3, 4 => 4}

map結合localstorage實現儲存操作用例

let contacts = new Map()
contacts.set('Jessie', {phone: "213-555-1234", address: "123 N 1st Ave"})
contacts.set('Hilary22',333) // undefined
contacts.set('Hilary', {phone: "617-555-4321", address: "321 S 2nd St"})
//contacts.get('Jessie') // {phone: "213-555-1234", address: "123 N 1st Ave"}

console.log(contacts)
console.log(JSON.stringify(Array.from(contacts.entries())))

window.localStorage.setItem('test',JSON.stringify(Array.from(contacts.entries())))

//console.log(new Map(JSON.parse(window.localStorage.getItem('test'))))
contacts = new Map(JSON.parse(window.localStorage.getItem('test')))
onsole.log( contacts  )

封裝storage

export default {
  setItem(key, item) {
    let stringifyItem;
    try {
      stringifyItem = JSON.stringify(item);
    } catch (error) {
      stringifyItem = '';
    } finally {
      window.localStorage.setItem(key, stringifyItem);
    }
  },
  getItem(key) {
    let item;
    try {
      const stringifyItem = window.localStorage.getItem(key);
      item = JSON.parse(stringifyItem);
    } catch (erorr) {
      item = null;
    }
    return item;
  },
  removeItem(key) {
    window.localStorage.removeItem(key);
  },
};

後續升級
達到一定量級,如果要做針對使用者層面的表格列操作快取,會考慮結合後端儲存使用indexDb儲存方式,支援G級別大小。