面试题答案
一键面试实现思路
- 数据结构设计:使用一个双向链表和一个哈希表来实现LRU。双向链表用于记录组件的使用顺序,哈希表用于快速定位组件在链表中的位置。
- 缓存命中处理:当访问一个缓存中的组件时,将其从当前位置移动到链表头部,表示最近使用。
- 缓存未命中处理:如果缓存已满,移除链表尾部的组件(最近最少使用),并将新组件添加到链表头部。
关键代码片段
- 双向链表节点类
class DoublyLinkedNode {
constructor(key, value) {
this.key = key;
this.value = value;
this.prev = null;
this.next = null;
}
}
- LRU缓存类
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
this.head = new DoublyLinkedNode(null, null);
this.tail = new DoublyLinkedNode(null, null);
this.head.next = this.tail;
this.tail.prev = this.head;
}
get(key) {
if (!this.cache.has(key)) {
return -1;
}
const node = this.cache.get(key);
this._moveToHead(node);
return node.value;
}
put(key, value) {
if (this.cache.has(key)) {
const node = this.cache.get(key);
node.value = value;
this._moveToHead(node);
} else {
const newNode = new DoublyLinkedNode(key, value);
this.cache.set(key, newNode);
this._addToHead(newNode);
if (this.cache.size > this.capacity) {
const removed = this._removeTail();
this.cache.delete(removed.key);
}
}
}
_addToHead(node) {
node.next = this.head.next;
node.prev = this.head;
this.head.next.prev = node;
this.head.next = node;
}
_removeNode(node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
_moveToHead(node) {
this._removeNode(node);
this._addToHead(node);
}
_removeTail() {
const removed = this.tail.prev;
this._removeNode(removed);
return removed;
}
}
- 在Vue应用中结合Keep - Alive使用
在Vue组件的生命周期钩子中,可以调用上述LRU缓存类的方法。例如,在
activated
钩子中标记组件被访问(调用get
方法),在deactivated
钩子中如果组件需要缓存则调用put
方法。
export default {
name: 'MyComponent',
data() {
return {
lruCache: new LRUCache(10) // 假设缓存容量为10
};
},
activated() {
this.lruCache.get(this.$route.path); // 假设以路由路径作为缓存键
},
deactivated() {
this.lruCache.put(this.$route.path, this); // 缓存当前组件实例
}
}
在实际应用中,还需要考虑如何与Vue的keep - alive
内置机制更好地集成,例如在组件被销毁时正确处理缓存等细节。