前端面试题详解整理66|LRU缓存,加载2048游戏时出现白屏,解决,前端性能监控,思维发散题,门守卫

182 阅读10分钟

25腾讯暑期实习前端一面凉经

第一次面试,人麻了发下面经给自己攒攒人品吧。
上来先四道题:

(1)LRU缓存,leetcode刷过2次,但是太紧张了没a出来;

LRU(Least Recently Used)缓存是一种常见的缓存替换算法,它的基本原理是删除最近最少使用的数据,保留最近使用的数据。LRU 缓存通常用于解决缓存容量有限的情况下,如何高效地管理缓存数据的问题。

LRU 缓存的实现通常基于哈希表和双向链表的组合,以实现高效的数据存储和访问。

实现思路:

  1. 使用哈希表存储键值对,键为缓存的键,值为指向双向链表节点的指针。
  2. 使用双向链表存储缓存数据,链表头部表示最近使用的数据,链表尾部表示最久未使用的数据。
  3. 当访问缓存中的数据时,如果数据存在,则将数据移动到链表头部;如果数据不存在,则返回空。
  4. 当插入新数据时,如果缓存已满,则删除链表尾部的数据,并从哈希表中删除对应的键值对;然后将新数据插入链表头部,并在哈希表中添加新的键值对。
  5. 哈希表和双向链表的操作都是 O(1) 复杂度的,因此整个 LRU 缓存的操作效率较高。

TypeScript 示例代码:

class LRUCache {
    private capacity: number;
    private cache: Map<number, number>;
    private order: number[];

    constructor(capacity: number) {
        this.capacity = capacity;
        this.cache = new Map();
        this.order = [];
    }

    get(key: number): number {
        if (this.cache.has(key)) {
            const index = this.order.indexOf(key);
            this.order.splice(index, 1);
            this.order.unshift(key);
            return this.cache.get(key);
        }
        return -1;
    }

    put(key: number, value: number): void {
        if (this.cache.has(key)) {
            this.cache.set(key, value);
            const index = this.order.indexOf(key);
            this.order.splice(index, 1);
            this.order.unshift(key);
        } else {
            if (this.cache.size === this.capacity) {
                const removedKey = this.order.pop();
                this.cache.delete(removedKey);
            }
            this.cache.set(key, value);
            this.order.unshift(key);
        }
    }
}

// 示例用法
const lruCache = new LRUCache(2);
lruCache.put(1, 1);
lruCache.put(2, 2);
console.log(lruCache.get(1)); // 输出 1
lruCache.put(3, 3); // 移除 key 2
console.log(lruCache.get(2)); // 输出 -1,因为 key 2 被移除
lruCache.put(4, 4); // 移除 key 1
console.log(lruCache.get(1)); // 输出 -1,因为 key 1 被移除
console.log(lruCache.get(3)); // 输出 3
console.log(lruCache.get(4)); // 输出 4

以上是一个简单的 TypeScript 实现示例,用于实现基本的 LRU 缓存功能。你可以根据具体需求进行扩展,例如添加更多的方法或改进性能。 以下是使用 JavaScript 实现的简单示例:

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

    get(key) {
        if (this.cache.has(key)) {
            const index = this.order.indexOf(key);
            this.order.splice(index, 1);
            this.order.unshift(key);
            return this.cache.get(key);
        }
        return -1;
    }

    put(key, value) {
        if (this.cache.has(key)) {
            this.cache.set(key, value);
            const index = this.order.indexOf(key);
            this.order.splice(index, 1);
            this.order.unshift(key);
        } else {
            if (this.cache.size === this.capacity) {
                const removedKey = this.order.pop();
                this.cache.delete(removedKey);
            }
            this.cache.set(key, value);
            this.order.unshift(key);
        }
    }
}

// 示例用法
const lruCache = new LRUCache(2);
lruCache.put(1, 1);
lruCache.put(2, 2);
console.log(lruCache.get(1)); // 输出 1
lruCache.put(3, 3); // 移除 key 2
console.log(lruCache.get(2)); // 输出 -1,因为 key 2 被移除
lruCache.put(4, 4); // 移除 key 1
console.log(lruCache.get(1)); // 输出 -1,因为 key 1 被移除
console.log(lruCache.get(3)); // 输出 3
console.log(lruCache.get(4)); // 输出 4

这段代码与 TypeScript 版本的实现类似,只是语法上有些差异。在 JavaScript 中,我们也可以通过使用 class 关键字和 Map 数据结构来实现 LRU 缓存。

(2)工程应用题,要解决2048游戏的两个bug,一个是加载出现白屏,另一个忘了。面试官分享了一个链接,是用vue3和typescript写的一个工程。用npm install后再npm run dev结果项目没运行,直接寄,而且我也不太会vue3和TS!

如果加载2048游戏时出现白屏,可能涉及到以下几个方面的问题:

  1. HTML 结构问题:

    • 检查游戏页面的 HTML 结构,确保包含了正确的游戏容器元素以及必要的样式和脚本引用。
  2. 样式问题:

    • 检查游戏页面的 CSS 样式表,确保样式文件被正确引入,并且游戏容器元素的样式设置正确,以确保游戏界面能够正常显示。
  3. JavaScript 代码问题:

    • 检查游戏的 JavaScript 代码,确保没有语法错误或逻辑错误,特别是在初始化游戏和渲染游戏界面的部分。
  4. 资源加载问题:

    • 检查游戏所需的图片、字体、音频等资源是否正确引入,并且路径设置正确,以确保这些资源能够被正确加载并显示在游戏界面上。
  5. 框架或库问题:

    • 如果游戏使用了框架或库(如 Vue.js、React、Angular 等),则需要确保框架或库的版本兼容性,并且正确引入并初始化。
  6. 浏览器兼容性问题:

    • 检查游戏在不同浏览器中的兼容性,特别是在一些旧版本的浏览器中是否能够正常加载和显示游戏界面。

解决这个问题的关键在于逐步排查可能引起白屏的原因,并逐一检查和修复。可以通过浏览器的开发者工具(比如 Chrome 的开发者工具)来查看加载过程中的报错信息,从而更准确地定位问题所在。如果问题比较复杂或难以定位,可以将代码分享给其他开发者进行协助分析和解决。

针对你提到的两个问题,我们可以逐一解决:

  1. 加载出现白屏:

    • 白屏通常是由于项目配置或代码中的错误导致的,可能涉及到路由配置、组件加载、样式问题等。
    • 首先,可以检查项目的入口文件(通常是 main.tsmain.js)以及路由配置文件,确保路由配置正确,指向了正确的组件。
    • 其次,检查浏览器的开发者工具(Console、Network 等选项卡)是否有报错信息,以便定位具体的错误。
    • 如果是组件加载或样式问题,可以检查组件代码和样式文件,确保路径正确、引入方式正确,并且没有错误的语法或逻辑问题。
  2. 项目无法运行:

    • 如果项目无法正常运行,可能是由于依赖安装不完整、配置错误或代码中存在错误等原因。
    • 首先,可以尝试重新执行 npm install 命令,以确保所有依赖包都已正确安装。
    • 其次,检查项目中的配置文件(如 package.jsontsconfig.json 等),确保配置项正确,并且与项目的实际情况相匹配。
    • 如果项目依赖于特定的 Node.js 版本或其他工具链,请确保你的开发环境中安装了正确版本的 Node.js,并且全局工具(如 vue-cli)已正确安装。
    • 最后,检查项目代码中是否存在语法错误、逻辑错误或依赖包版本不兼容等问题,并尝试根据报错信息进行修复。

如果你不熟悉 Vue.js 3 和 TypeScript,可以尝试先了解它们的基本概念和语法规则,然后查阅相关文档和教程,以便更好地理解项目代码和解决问题。另外,你也可以向面试官提出具体的问题或困惑,他们可能会提供更多的帮助和指导。

(3)前端性能监控方面的,要求实现一个方法可以自动打点,把性能反馈给日志或者后端,额。。。不会。。。

要实现自动打点并将性能数据反馈给日志或后端,可以考虑以下步骤:

  1. 选择合适的性能指标:

    • 确定需要收集的性能指标,比如页面加载时间、DOM 渲染时间、资源加载时间、用户交互响应时间等。
  2. 编写打点函数:

    • 编写一个打点函数,用于在关键位置调用,并在其中收集性能数据。可以使用浏览器提供的 Performance API 来获取性能数据,比如 performance.now() 方法来获取时间戳。
  3. 发送数据到后端:

    • 在打点函数中,将收集到的性能数据发送到后端。可以使用 XMLHttpRequest 或 Fetch API 发送 POST 请求,将数据发送给服务器。在服务器端,可以将数据写入日志文件或存储到数据库中。
  4. 错误处理:

    • 考虑到网络请求可能会失败,需要在代码中添加错误处理机制,确保性能数据能够成功发送到后端。可以添加重试机制或者记录错误日志。

下面是一个简单的示例代码,演示了如何实现自动打点并将性能数据发送到后端:

function sendPerformanceData(data) {
    // 使用 XMLHttpRequest 发送 POST 请求
    const xhr = new XMLHttpRequest();
    xhr.open('POST', '/log-performance', true);
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.onreadystatechange = function() {
        if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
            console.log('Performance data sent successfully');
        } else {
            console.error('Failed to send performance data');
        }
    };
    xhr.send(JSON.stringify(data));
}

function trackPerformance() {
    const startTime = performance.now();

    // 模拟耗时操作
    for (let i = 0; i < 1000000; i++) {
        Math.sqrt(i);
    }

    const endTime = performance.now();
    const elapsedTime = endTime - startTime;

    // 收集性能数据并发送到后端
    const performanceData = {
        startTime: startTime,
        endTime: endTime,
        elapsedTime: elapsedTime
    };
    sendPerformanceData(performanceData);
}

// 在需要打点的地方调用 trackPerformance 函数
trackPerformance();

这段代码会在调用 trackPerformance() 函数时执行耗时操作,并在操作完成后将性能数据发送到后端。你可以根据具体的需求和项目情况,调整代码逻辑和收集的性能数据。

(4)思维发散题。有两个门,一扇通往自由,一扇进了就出不去。有两个守卫,一个只会说真话,另一个只说假话。可以问一个问题,思路是什么。没有一点思路

要找出通往自由的门,可以通过以下思路:

  1. 选择一扇门进入:

    • 首先,选择一扇门进入,不妨称之为门 A。
  2. 询问其中一个守卫:

    • 选择其中一个守卫,向其询问一个问题,比如: "如果我问另一个守卫,他会告诉我哪扇门通往自由?"
  3. 分析守卫的回答:

    • 如果这个守卫是说真话的,他会告诉你另一个守卫会指向哪扇门。

      • 如果这扇门通往自由,那么他会告诉你另一个守卫会指向通往自由的门,这意味着门 A 通往自由。
      • 如果这扇门进了就出不去,那么他会告诉你另一个守卫会指向通往自由的门,这是一个矛盾的情况,因为另一个守卫会指向另一扇门,所以门 A 通往自由。
    • 如果这个守卫是说假话的,他会告诉你另一个守卫会指向哪扇门。

      • 如果这扇门通往自由,那么他会告诉你另一个守卫会指向通往自由的门,这是一个矛盾的情况,因为另一个守卫会指向另一扇门,所以门 A 通往自由。
      • 如果这扇门进了就出不去,那么他会告诉你另一个守卫会指向通往自由的门,这意味着门 A 通往自由。

根据上述分析,通过向一个守卫询问问题,即可找到通往自由的门。因为无论这个守卫是说真话还是说假话,最终结果都是一致的。

做了快50分钟,顶不住了,和面试官说做不下去了。面试官问了下几个题的思路,然后开始聊天。先问了下为什么想找前端工作,然后问项目是Vue2的,有没有用过Vue3,它们有什么区别。聊了10几分钟就结束了。
面试官挺好的,但是过程太难顶了。八股没问,项目也没咋问。估计是一道题没a出来,也没什么好问的了。还是太菜了,菜就多学

作者:coderMine
链接:www.nowcoder.com/feed/main/d…
来源:牛客网