前端面试题详解整理46|括号匹配合并,首屏加载过慢,中央事件总线eventbus,单页面开发spa,

76 阅读9分钟

快手前端实习面试复盘 (估计凉了)

面试官前半小时不问八股文,反而问我数据分析、爬虫之类的问题…直到后面半小时才逐渐开始步入正题:

1. 什么是中央事件总线eventbus

中央事件总线(EventBus)是一种用于在应用程序中进行组件间通信的模式。它允许不同组件之间通过事件的发布和订阅来进行解耦和通信,从而简化了组件之间的关联性。

基本上,中央事件总线由以下几个核心组件构成:

  1. 事件(Event): 事件是指应用程序中发生的特定动作或状态变化。它可以是任何类型的动作,例如用户点击按钮、数据加载完成等。事件通常由一个唯一的名称标识。

  2. 事件发布者(Event Publisher): 事件发布者是指负责发出(发布)事件的组件。当特定条件满足时,事件发布者将事件发布到事件总线上。

  3. 事件订阅者(Event Subscriber): 事件订阅者是指希望在特定事件发生时被通知的组件。它通过订阅特定事件来表明自己对该事件感兴趣,并定义处理该事件的回调函数。

  4. 事件总线(Event Bus): 事件总线是承载事件流的中央通道。它负责管理所有事件的订阅和发布,并确保事件的正确传递。

使用中央事件总线的优点包括:

  • 解耦性:组件之间的通信变得更加解耦,不需要直接引用或依赖其他组件。
  • 灵活性:可以轻松地添加、删除或更改事件,而不影响应用程序的其他部分。
  • 可维护性:由于事件是基于名称的,因此可以更轻松地理解和维护代码。

虽然中央事件总线在某些情况下可以简化应用程序的设计,但也存在一些缺点,如可能导致代码的调试和维护困难,以及可能引入全局状态管理的问题。因此,在使用中央事件总线时需要谨慎考虑,并根据具体情况权衡利弊。

        协助组件进行通讯的工具。实际上是通过创建一个新的vm对象,专门统一注册事件,供所有组件共同操作,达到所有组件随意隔代传值的效果。
2. 什么是发布订阅模式
3. 手撕发布订阅

发布订阅模式是一种设计模式,用于实现对象之间的解耦和通信。在这种模式中,有一个事件的发布者(发布者)和多个订阅者(订阅者)。发布者负责发出事件,而订阅者则负责订阅感兴趣的事件并执行相应的操作。当事件发生时,发布者会通知所有订阅者,并执行相应的处理逻辑。

这种模式的核心是事件的分发和订阅机制。发布者不需要知道订阅者的具体信息,而是将事件发布到一个中间的通道(或称为事件总线),订阅者则通过订阅感兴趣的事件来接收通知。这样就实现了发布者和订阅者之间的解耦,使得系统更加灵活和可扩展。

在 JavaScript 中,可以使用发布订阅模式来实现事件的分发和订阅。下面是一个简单的手撕发布订阅模式的实现:

class EventBus {
  constructor() {
    this.events = {};
  }

  // 订阅事件
  subscribe(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  }

  // 取消订阅
  unsubscribe(event, callback) {
    if (this.events[event]) {
      this.events[event] = this.events[event].filter(cb => cb !== callback);
    }
  }

  // 发布事件
  publish(event, data) {
    if (this.events[event]) {
      this.events[event].forEach(callback => callback(data));
    }
  }
}

// 使用示例
const eventBus = new EventBus();

// 订阅事件
eventBus.subscribe('userLoggedIn', (data) => {
  console.log('User logged in:', data);
});

// 发布事件
eventBus.publish('userLoggedIn', { username: 'example' });

在这个示例中,EventBus 类实现了发布订阅模式的核心功能。通过 subscribe 方法订阅事件,通过 publish 方法发布事件,并通过 unsubscribe 方法取消订阅。通过这种方式,可以实现对象之间的解耦和通信。

5. 你的项目在哪里需要优化(多说多措。。。。)

6. 什么是单页面开发

单页面应用(SPA)是一种 web 应用程序架构,它通过使用动态的 HTML、CSS 和 JavaScript 在同一个 web 页面中加载所有必要的代码和资源,从而实现了在不刷新整个页面的情况下进行页面的切换和内容的更新。在单页面应用中,页面的切换和内容的更新是通过 JavaScript 动态加载并替换页面的部分内容来实现的,而不是通过传统的页面跳转。

单页面应用的特点包括:

  1. 单页面加载:整个 web 应用程序的代码和资源只会在用户第一次访问时加载一次,之后页面的切换和内容的更新都是通过 AJAX 或路由的方式在当前页面中动态加载并替换部分内容。

  2. 动态路由:单页面应用通常使用前端路由器(如 React Router、Vue Router 等)来管理页面的路由,根据 URL 的变化来动态加载相应的组件或页面内容。

  3. 异步加载:单页面应用中的资源(如 JavaScript、CSS、图片等)通常采用异步加载的方式加载,以提高页面的加载速度和性能。

  4. 前端渲染:单页面应用中的页面通常由前端 JavaScript 负责渲染,服务器端只负责提供数据接口,前端通过 AJAX 请求获取数据并动态渲染页面内容。

  5. 良好的用户体验:由于单页面应用不需要重新加载整个页面,页面切换和内容更新都是在前端完成的,因此具有较快的响应速度和更流畅的用户体验。

单页面应用的优点包括:

  • 较快的加载速度:由于整个应用程序的代码和资源只加载一次,因此页面切换和内容更新通常会更快。
  • 更流畅的用户体验:页面切换和内容更新都是在前端完成的,用户不会感觉到页面的刷新,因此具有更流畅的用户体验。
  • 更好的交互性:可以实现更丰富和复杂的交互效果,如动态加载、页面过渡、无刷新提交等。

然而,单页面应用也存在一些缺点,如对 SEO 不友好、首屏加载时间可能较长、对浏览器的性能要求较高等。因此,在选择使用单页面应用时需要根据具体的需求和项目情况进行权衡。

8. 如何解决首屏加载过慢问题

解决单页面应用(SPA)首屏加载过慢的问题通常可以从以下几个方面着手:

  1. 代码优化

    • 代码分割(Code Splitting):将应用程序的代码按照逻辑分割成多个小块,并按需加载。这样可以减少首屏需要加载的代码量,提高加载速度。
    • 懒加载(Lazy Loading):延迟加载页面中不必要的组件、资源和功能,只在需要时再进行加载。这样可以减少首屏加载时需要下载的资源量,加快页面加载速度。
    • 压缩和精简代码:尽量减少不必要的代码和资源,压缩和精简代码文件,减小文件大小,提高加载速度。
  2. 资源优化

    • 图片优化:使用适当的图片格式和压缩率,减小图片大小,提高加载速度。
    • 字体优化:选择合适的字体格式和加载方式,减少字体文件的大小和数量。
    • 文件缓存:利用浏览器缓存机制,将静态资源文件进行缓存,减少重复加载,提高加载速度。
  3. 网络优化

    • CDN 加速:使用内容分发网络(CDN)来加速静态资源文件的传输,提高加载速度。
    • HTTP/2 协议:使用 HTTP/2 协议来减少网络请求的数量和延迟,提高页面加载速度。
    • 资源预加载:使用 <link rel="preload"><link rel="prefetch"> 预加载页面所需的关键资源,加快资源获取速度。
  4. 服务器优化

    • 服务器端渲染(SSR):考虑使用服务器端渲染来提前生成首屏所需的 HTML 内容,减少客户端渲染的时间,提高首屏加载速度。
    • 服务端缓存:利用服务端缓存技术(如缓存页面片段、数据缓存等)来加速页面的生成和返回。
  5. 性能监控和优化

    • 性能监控工具:使用性能监控工具(如 Chrome 开发者工具、Lighthouse 等)来分析页面加载性能,找出性能瓶颈并进行优化。
    • 前端性能优化技巧:掌握一些前端性能优化的常用技巧,如合并请求、减少重绘和回流、减少 JavaScript 执行时间等。

通过综合使用以上优化技术和方法,可以有效地提高单页面应用的首屏加载速度,提升用户体验。

10. 算法题:字符串由(){}[]组成,判断字符串是否括号是否能够合并并且能够正确合并(最开始题目读错了,后面才改过来)

这个问题可以使用栈(Stack)来解决。具体的思路是遍历字符串,遇到左括号就将其压入栈中,遇到右括号则判断与栈顶元素是否匹配,如果匹配则弹出栈顶元素,否则返回 false。最后检查栈是否为空,如果为空则说明所有括号都能够正确匹配,否则返回 false。

下面是用 JavaScript 实现的代码:

function isValidParentheses(s) {
    const stack = [];
    const map = {
        '(': ')',
        '{': '}',
        '[': ']'
    };
    
    for (let i = 0; i < s.length; i++) {
        const char = s[i];
        if (map[char]) {
            stack.push(char);
        } else {
            const top = stack.pop();
            if (map[top] !== char) {
                return false; // 括号不匹配
            }
        }
    }
    
    return stack.length === 0; // 栈为空说明所有括号都正确匹配
}

// 测试
console.log(isValidParentheses("()")); // true
console.log(isValidParentheses("()[]{}")); // true
console.log(isValidParentheses("(]")); // false
console.log(isValidParentheses("([)]")); // false
console.log(isValidParentheses("{[]}")); // true

这段代码通过遍历字符串,使用栈来保存左括号,并在遇到右括号时进行匹配判断。时间复杂度为 O(n),其中 n 是字符串的长度。

总共1h5min……准备了好久的八股文前半个小时一个也不问,不过后面回答得确实也不太好,唉,继续加油吧…

作者:给我一个offer又能怎样
链接:www.nowcoder.com/feed/main/d…
来源:牛客网