面经:好未来前端面经

908 阅读12分钟

面试题目

1、vue组件怎么透传

2、vue组件缓存

3、第一次进入缓存组件的生命周期

4、keep-alive生命周期

5、如何缓存多层路由的组件,超过两层会有问题

6、怎么封装组件库 怎么打包到cdn

7、怎么获取组件库组件自带的属性

8、长轮训和短轮询区别

9、websocket

10、微前端应用之间传参

11、session能不能不同域名

12、大文件上传,原理,怎么保证准确

13、文件预览

14、node调小键盘

15、Electron 的主进程和渲染进程

16、如何在 Electron 中进行远程通信?

17、electron应用怎么做更新!!

面试详解

1、vue组件怎么透传

透传 attribute 指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute(属性) 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。

当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上

如果一个子组件的根元素已经有了 class 或 style attribute,它会和从父组件上继承的值合并

// 父组件中这样透传
<MyButton class="large" />

<!-- <MyButton> 的模板 -->
<button class="btn">Click Me</button>

// 则最后渲染出的 DOM 结果会变成
<button class="btn large">Click Me</button>
  • 这些透传进来的 attribute 可以在模板的表达式中直接用 $attrs 访问到。
  • 这个 $attrs 对象包含了除组件所声明的 props 和 emits 之外的所有其他 attribute,例如 class,style,v-on 监听器等等。
  • attrs 不提供验证或默认值
  • attrs 不是响应性的,不能像props一样跟踪它的变化。

2、vue组件缓存

组件缓存通常指的是在组件切换时保留其状态,避免重新渲染或重新执行某些耗时操作

Vue的<keep-alive>元素可以缓存不活动的组件实例,避免反复销毁和重建,适用于组件状态需要保留的情况。

3、第一次进入缓存组件的生命周期

1、beforeCreate:在组件实例初始化之后被调用。此时,组件的数据选项尚未被处理

2、created:在组件实例创建完成后被调用。这时,组件的实例已完全创建好,但是组件尚未挂载到DOM上

3、beforeMount:在挂载开始之前被调用。此时,相关的DOM还未创建。

4、mounted:在组件被挂载到DOM后立即被调用

5、activated:当组件被 <keep-alive> 缓存并首次激活时调用。这类似于 mounted,但仅用于被 <keep-alive> 包裹的组件。

6、deactivated: 当组件被 <keep-alive> 缓存并首次停用时调用。这通常发生在组件被 <keep-alive> 包裹且从页面上移除时。

当组件被 <keep-alive> 包裹时,直接的组件切换不会触发 destroyed 钩子,因为组件实例实际上并没有被销毁,而是被缓存起来了。只有当组件实例最终被 <keep-alive> 排除缓存时,destroyed 钩子才会被调用。

此外,如果组件在 <keep-alive> 中被重新激活,它将不会再次经过 created 和 mounted 钩子,而是会调用 activated 钩子。如果组件被 <keep-alive> 停用,将调用 deactivated 钩子。

4、keep-alive生命周期

1、activated:当使用 <keep-alive> 包裹的组件第一次被激活,或者从停用状态变为激活状态时调用

2、deactivated:当使用 <keep-alive> 包裹的组件从激活状态变为停用状态时调用。这通常发生在组件被 <keep-alive> 包裹且从页面上移除时

5、如何缓存多层路由的组件,超过两层会有什么问题

1、使用<keep-alive>包裹路由出口

<template>
  <keep-alive>
    <router-view />
  </keep-alive>
</template>

2、使用<keep-alive>的include和exclude属性: 可以使用include属性来指定需要缓存的组件名,或者使用exclude属性来排除不需要缓存的组件。

<keep-alive include="ChildA,ChildB">
  <!-- 只有ChildA和ChildB会被缓存 -->
  <router-view />
</keep-alive>

超过两层的嵌套路由可能会遇到的问题:

  • 内存使用: 缓存多层嵌套组件可能会导致内存使用增加,特别是当这些组件包含大量状态或数据时。
  • 组件状态管理: 多层嵌套组件可能会使组件状态管理变得更加复杂,特别是当组件间存在状态共享或依赖时。
  • 数据同步问题: 如果缓存的组件内部数据依赖于外部数据,可能需要额外的逻辑来确保数据在路由切换时保持同步。
  • 组件更新问题: 当父组件重新渲染时,被<keep-alive>缓存的子组件可能不会重新渲染,这可能会导致显示过时的数据。
  • 导航逻辑复杂性: 多层嵌套的组件可能会使导航守卫和路由配置变得更加复杂。
  • 性能考虑: 虽然<keep-alive>可以提高性能,但如果不正确使用,也可能导致性能问题,比如不必要的内存占用。
  • 组件激活和停用: 使用<keep-alive>时,需要正确处理组件的activated和deactivated生命周期钩子,以确保组件在激活和停用时执行正确的逻辑。

6、怎么封装组件库 怎么打包到cdn

package.json中填一些基本信息 在命令行里登录npm账号,package.json中author尽量与npm账户一致

npm adduser    
Username: your name
Password: your password 
Email: yourmail

配置成功之后提交代码

npm publish

如果提示包不能为private,需要执行下面的发布方式:

npm publish --access public

7、websocket

WebSocket是一种网络通信协议,它提供了一个全双工通信渠道,通过一个单一的长期连接允许服务器主动向客户端发送消息。WebSocket 用于实现实时通信。

特点:

  • 全双工通信:WebSocket连接允许服务器和客户端之间双向交互,与HTTP请求-响应模式不同。
  • 持久连接:一旦建立WebSocket连接,它会保持开放,直到客户端或服务器端明确关闭连接。
  • 实时性能:WebSocket用于需要快速实时通信的应用,如在线游戏、聊天应用、实时数据传输等。
  • 较少的开销:与HTTP相比,WebSocket通信不需要每次请求都携带HTTP头部,因此开销较小。
  • 基于文本或二进制:WebSocket允许传输文本数据(JSON格式常见)和二进制数据。
  • 安全性:WebSocket连接可以通过wss://(WebSocket Secure)使用TLS/SSL加密,确保数据传输安全。
// 创建一个新的WebSocket对象
const socket = new WebSocket('ws://example.com/socketserver');

// 监听连接打开事件
socket.addEventListener('open'function (event) {
  // 向服务器发送消息
  socket.send('Hello Server!');
});

// 监听消息事件
socket.addEventListener('message'function (event) {
  // 接收服务器发送的消息
  console.log('Message from server:', event.data);
});

// 监听错误事件
socket.addEventListener('error'function (event) {
  console.error('WebSocket error:', event);
});

// 监听连接关闭事件
socket.addEventListener('close'function (event) {
  console.log('WebSocket connection closed:', event.code, event.reason);
});

// 在适当的时候关闭连接
// socket.close();

8、WebSocket协议使用哪个端口

通常WebSocket使用端口80,而加密的WebSocket(wss://)使用端口443。

9、 长轮训和短轮询区别

短轮询(Short Polling):

  • 频繁请求:客户端以固定的时间间隔(如每秒钟)向服务器发送请求,无论服务器是否有更新。
  • 响应速度:如果服务器没有新数据,它会立即响应一个空的结果,客户端接收到空结果后再发起新的请求。
  • 服务器负载:由于请求频繁,即使没有数据更新,也可能导致服务器负载较高。
  • 实时性:实时性较差,因为数据更新有固定的延迟(等于轮询间隔)。
  • 示例场景:适合数据更新不频繁且实时性要求不高的场景。

长轮询(Long Polling)

  • 等待响应:客户端发送请求到服务器后,服务器会保持请求打开,直到有数据更新或超时。
  • 减少请求次数:只有当数据更新或连接超时时,服务器才响应请求,然后客户端立即发送新的请求。
  • 服务器负载:相比短轮询,长轮询减少了请求次数,降低了服务器的负载。
  • 实时性:实时性较好,因为数据更新时客户端能够立即接收到响应。
  • 示例场景:适合数据更新频繁且需要较好实时性的场景。

10、微前端应用之间怎么传参

微前端:将大型的前端应用程序分解为更小、更易于管理的独立前端应用程序。可以独立开发、测试、部署和维护。

常见的通信方式包括事件总线、全局状态管理、Web Components等。

  • 全局事件总线 Event Bus
  • 共享状态管理:使用共享的状态管理库(如Redux或Vuex),在多个应用之间共享状态。
  • 将数据存储在Cookie或LocalStorage中,不同的应用可以访问这些存储的数据。
  • 通过URL传递参数,其他应用可以通过解析URL来获取参数
  • 通过iframe嵌入,可以使用window.postMessageAPI在父页面和iframe之间安全地传递消息。

11、session能不能不同域名

Session本身是与特定域名和路径关联的,由设置Session的Cookie的域(Domain)和路径(Path)属性决定。默认情况下,Session Cookie只在创建它的域名和路径下有效。

如果需要在相同的主域下的不同子域之间共享Session,可以在Cookie的Domain属性中设置主域,这样所有子域都可以访问Session。

12、大文件上传原理

原理:

  • 客户端分片:大文件在客户端被分割成多个小块(片),每一片单独上传。
  • 并行上传:利用多线程或JavaScript的XMLHttpRequest/fetch API并行上传这些分片,提高上传效率。
  • 服务器端接收:服务器端接收这些分片,并按照正确的顺序重新组装它们。
  • 分片校验:每个分片可以包含校验信息(如MD5哈希),以确保上传过程中的数据完整性。
  • 断点续传:如果上传过程中断,客户端可以从中断的地方重新开始上传,而不是重新上传整个文件。
  • 上传完成:所有分片上传完毕后,服务器端发送响应,告知客户端上传状态。

13、怎么保证准确

为整个文件上传过程生成一个唯一标识符,用于识别和管理分片,对每个分片生成校验码(如MD5),在上传完成后进行服务器端验证,

14、node调起虚拟键盘

使用新的进程来运行命令

  • exec() 和 .execSync():用于创建与父进程的I/O保持连接的子进程,通常用于执行shell命令。
const { exec } = require('child_process');

// Windows系统下显示虚拟键盘
exec('osk');

15、Electron 的主进程和渲染进程

主进程 (Main Process)

  • 单个实例:Electron 应用通常只有一个主进程实例,运行在 main.js 文件中。
  • 应用生命周期管理:主进程负责管理应用的生命周期,包括初始化、运行和退出。
  • 创建窗口:主进程负责创建和控制浏览器窗口(BrowserWindow)。
  • 原生Node.js模块:主进程可以访问所有原生Node.js模块,用于执行文件系统操作、网络请求等。
  • IPC通信:主进程可以通过进程间通信(IPC)与渲染进程或其他主进程实例通信。
  • 安全性:主进程中运行的代码具有访问系统资源的能力,因此安全性非常重要,要避免执行不受信任的代码。

渲染进程 (Renderer Process)

  • 多个实例:每个浏览器窗口或网页视图(标签)都有自己的渲染进程。
  • Chromium 内核:渲染进程使用 Chromium 内核来渲染HTML、CSS和JavaScript,就像普通的网页浏览器一样。
  • 隔离环境:每个渲染进程都是隔离的,有自己的V8引擎实例和全局作用域。
  • 访问限制:出于安全考虑,渲染进程不能直接访问Node.js的核心模块。它们通常用于执行客户端脚本和用户界面逻辑。
  • IPC通信:渲染进程可以通过IPC与主进程通信,请求执行一些需要Node.js能力的后台任务。
  • Web技术:渲染进程中的代码可以使用所有标准的Web技术,包括HTML5、CSS3和JavaScript。

16、如何在 Electron 中进行远程通信?

通过预加载脚本将主进程和渲染进程连接起来进行通信

单向通信:

  • 在预加载文件里暴露方法,使用ipcRenderer.send向主进程发送消息,在渲染进程中调用这个方法
  • 在主进程中用 ipcMain.on接收消息,进行操作

双向通信:

  • 在预加载文件里暴露方法,使用ipcRenderer.invoke向主进程发送消息,在渲染进程中调用这个方法
  // preload脚本暴露方法
  const { contextBridge, ipcRenderer } = require('electron/renderer')

contextBridge.exposeInMainWorld('electronAPI', {
  setTitle(title) => ipcRenderer.send('set-title', title),
  postMessage() => ipcRenderer.invoke('post-message')
})
// 渲染进程调用方法
ipcMain.handle('post-message'async ()=>{
    return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('支付宝到账100万元');
        }, 2000);
      });
})
  
  • 在主进程中用 ipcMain.handle接收消息,进行操作
  // 主进程中监听方法
  ipcMain.handle('post-message'async ()=>{
    return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('支付宝到账100万元');
        }, 2000);
      });
})

区别:

  • ipcRenderer.send: 发送消息后不返回任何值,它是单向的,发送消息到主进程后不会等待主进程的响应。
  • ipcRenderer.invoke: 发送消息后会返回一个 Promise,该 Promise 在主进程处理完成后被解析,可以获取到主进程返回的结果。
  • 对于 ipcRenderer.send,主进程通过 ipcMain.on 来监听并处理消息。
  • 对于 ipcRenderer.invoke,主进程通过 ipcMain.handle 来注册处理程序,处理程序返回的 Promise 在处理完成后被解析,将结果返回给渲染进程。

还有一种方法:使用 WebContents 的 postMessage 和 on 事件

  1. 在主进程中使用 webContents 发送消息:主进程可以通过 webContents 的 postMessage 方法向渲染进程发送消息。
// 主进程 (main.js)
const { webContents } = require('electron');
const contents = webContents.fromId(id); // 替换 id 为你的渲染进程的 ID
contents.postMessage('message-from-main''*');

2. 在渲染进程中监听消息:渲染进程可以使用 window 的 on 事件监听器来监听主进程的消息。

// 渲染进程 (renderer.js 或 index.html 中的 <script> 标签)
window.on('message'(event, message) => {
console.log('收到来自主进程的消息:', message);
});

17、electron应用怎么做更新!!

Electron 内置了 autoUpdater 模块,它利用 GitHub Releases 或自建服务器的方式获取新版本信息并进行更新。当检测到新版本时,它能自动下载并安装新的更新包,从而实现了无缝、便捷的更新体验。

使用 electron-builder 等打包工具生成新的安装包或更新包,将其上传至 GitHub Releases 或其他指定服务器。