面试题[前端项目相关]
1. 前端项目基础
1.1 模块化
1.2 微前端
1.3 低代码
组成结构:工具栏、物料区、渲染器、设置器。
1.4 前端埋点
1.5 前端监控
1.6 权限管理
1.7 单点登录
1.8 设计模式
设计模式有哪些?
32种设计模式是根据什么来的?(6大程序设计原则和23种设计模式)
2. 前端项目进阶
2.1 安全问题
2.1.1 有哪些可能引起前端安全的问题
- 跨站脚本攻击(Cross-Site Scripting,XSS):⼀种代码注入方式,为了与 CSS 区分所以被称作 XSS。早期常见于网络论坛,起因是网站没有对用户的输⼊进行严格的限制,使得攻击者可以将脚本上传到帖子让其他人浏览到有恶意脚本的页面,其注入方式很简单包括但不限于 JavaScript / CSS / Flash 等;
- 跨站请求伪造(Cross-Site Request Forgeries,CSRF):指攻击者通过设置好的陷阱,强制对已完成认证的用户进行非预期的个人信息或设定信息等某些状态更新,属于被动攻击;
- iframe 的滥用:iframe 中的内容是由第三方来提供的,默认情况下他们不受控制,他们可以在 iframe 中运行 JavaScript 脚本、Flash 插件、弹出对话框等等,这可能会破坏前端用户体验;
- 恶意第三方库:无论是后端服务器应用还是前端应用开发,绝大多数时候都是在借助开发框架和各种类库进行快速开发,⼀旦第三方库被植入恶意代码很容易引起安全问题。
2.1.2 前端和服务端交互的时候,如何保证数据的安全性?不被第三方修改
- 使用加密通信:使用安全的通信协议(如HTTPS)来加密数据传输,确保数据在传输过程中不被窃听或篡改。加密通信可以使用传输层安全性协议(TLS)来实现。
- 身份验证和授权:确保只有经过身份验证的用户才能访问和操作数据。使用安全的身份验证机制,如用户名和密码、令牌或证书,来验证用户身份,并使用权限控制机制确保用户只能访问其授权范围内的数据。
- 输入验证和过滤:对于来自用户的输入数据,进行严格的验证和过滤,以防止恶意输入或注入攻击。使用安全编码实践来处理和验证输入,确保只接受符合预期格式和内容的数据。
- 数据加密:对于敏感数据,可以在存储和传输之前对其进行加密。使用强大的加密算法和安全密钥管理来确保数据在存储和传输过程中的安全性。
- 安全审计和监控:实施日志记录、审计和监控机制,以便检测和响应潜在的安全威胁。监控系统的活动并记录关键事件,以便进行后续分析和调查。
- 更新和安全补丁:及时更新和应用软件、框架和库的安全补丁,以确保系统中的漏洞和安全漏洞得到修复。
- 安全培训和意识:对开发人员和用户进行安全培训,提高他们对数据安全的意识和理解,并教授安全最佳实践。
2.1.3 Token 可以放在 Cookie 里吗
当被问这个问题的时候,第一时间要想到安全问题。通常回答不可以,因为存在 CSRF(跨站请求伪造)风险,攻击者可以冒用 Cookie 中的信息来发送恶意请求。解决 CSRF 问题,可以设置同源检测(Origin 和 Referer 认证),也可以设置 Samesite 为 Strict。
2.1.4 为什么用户信息 Cookie 应由后端来配置
Cookie的设置机制
Cookie是HTTP协议中的一部分,用于在客户端(通常是浏览器)存储少量数据。这些数据可以包括用户的偏好设置、用户名、会话ID等。当服务器需要向客户端发送数据时,可以通过设置HTTP响应头中的
Set-Cookie字段来实现。这一机制决定了Cookie的设置通常由服务器(即后端)来完成。用户认证和会话管理的需要
- 用户认证:在用户登录过程中,后端服务器会验证用户的身份,并生成一个包含用户身份验证信息的Cookie。这个Cookie随后被发送到客户端,并在后续的请求中用于验证用户的身份。通过这种方式,服务器可以确保只有经过认证的用户才能访问受保护的资源。
- 会话管理:Cookie还用于会话管理,即跟踪用户在网站上的活动状态。后端服务器通过为每个用户会话分配一个唯一的会话ID,并将其存储在Cookie中,来保持对用户会话的跟踪。这样,当用户在不同页面之间导航时,服务器可以通过读取Cookie中的会话ID来识别用户,并维护其会话状态。
安全性和隐私性的考虑
- 防止篡改:后端设置Cookie时,可以对其进行签名或加密,以确保Cookie在传输过程中不会被篡改。这种安全性措施对于保护用户数据的完整性至关重要。
- 遵循隐私法规:随着隐私保护法规(如GDPR)的出台,网站需要确保在收集和使用用户数据时遵守相关法规。后端设置Cookie可以更容易地实现这一点,因为后端服务器可以控制和记录Cookie的使用情况,并确保在必要时获得用户的同意。
前后端协作与一致性
在Web应用程序中,前端和后端通常需要进行紧密的协作。后端负责处理数据和业务逻辑,而前端负责呈现用户界面和与用户交互。通过后端设置Cookie,可以确保前后端在用户认证和会话管理方面的一致性,从而避免潜在的冲突和错误。
综上所述,用户信息的Cookie需要通过后端来设置,这既符合Cookie的设置机制,也满足了用户认证、会话管理、安全性和隐私性等方面的需求。同时,这种做法还有助于确保前后端在用户状态管理方面的一致性和准确性。
2.1.5 AccessToken 与 RefreshToken 的双重作用
在用户认证和会话管理的场景中,后端配置Cookie并返回两种token(accessToken和refreshToken)的做法是出于安全性和便利性的考虑。以下是对这种做法的详细解释:
- Cookie的作用与配置
- 作用:Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。Cookie主要用于辨识用户身份、会话跟踪、存储用户偏好设置等。
- 配置:后端服务器会配置Cookie的相关属性,如域名、路径、有效期、安全标志(HttpOnly、Secure)等,以确保Cookie的安全性和正确性。
- accessToken和refreshToken的作用
- accessToken
- 定义:accessToken是用来对客户端进行认证的令牌,类似于密码,有一定的有效期。
- 作用:客户端在获取到accessToken后,可以将其携带在请求头中,用于向受保护的资源服务器发送请求并获取用户的数据。
- 有效期:accessToken的有效期通常较短,如几分钟到几小时不等,这是为了降低令牌被泄露或滥用的风险。
- refreshToken
- 定义:refreshToken是用于更新accessToken的令牌,具有相对较长的有效期。
- 作用:当accessToken过期后,客户端可以使用refreshToken向授权服务器请求新的accessToken,而无需再次请求用户的授权。
- 有效期:refreshToken的有效期通常较长,如几天到几个月不等,这取决于应用的安全需求和业务逻辑。
- accessToken
- 返回两种token的原因
- 安全性:通过分离accessToken和refreshToken,可以降低令牌被泄露的风险。即使accessToken被泄露,由于它的有效期较短,攻击者也只能在有限的时间内使用它。而refreshToken由于有效期较长且通常不直接用于访问受保护的资源,因此其泄露的风险相对较低。
- 便利性:使用refreshToken可以自动更新accessToken,而无需用户重新登录或授权。这提高了用户体验和应用的可用性。
- 控制访问权限:通过管理accessToken和refreshToken的有效期和刷新策略,后端可以更精细地控制客户端对受保护资源的访问权限。
- 实际应用中的注意事项
- 存储与传输:accessToken和refreshToken通常会在客户端的浏览器中以Cookie或localStorage等形式存储,并在需要时通过HTTP请求头传输给服务器。
- 刷新策略:建议在accessToken过期前的一段时间内(如30分钟)使用refreshToken刷新accessToken,以确保客户端始终持有有效的访问令牌。
- 安全性增强:为了增强安全性,可以将refreshToken设置为HttpOnly和Secure标志,以防止跨站脚本攻击(XSS)和通过不安全的网络传输泄露。
综上所述,后端配置Cookie并返回两种token(accessToken和refreshToken)的做法是为了在保障安全性的同时提高用户体验和应用的可用性。
2.1.6 RefreshToken 无感刷新
refreshToken的无感刷新是一种提升用户体验的重要机制,它允许客户端在accessToken过期时自动使用refreshToken获取新的accessToken,而无需用户重新登录或进行其他手动操作。以下是实现refreshToken无感刷新的步骤和注意事项:
实现步骤
- 存储
refreshToken:- 在用户成功登录后,后端服务器会生成并返回
accessToken和refreshToken。 - 客户端(如浏览器)需要安全地存储这两个令牌,通常是在浏览器的
localStorage、sessionStorage或Cookie中。
- 在用户成功登录后,后端服务器会生成并返回
- 配置请求拦截器:
- 客户端配置网络请求库(如axios)的请求拦截器,以便在发送请求时自动携带
accessToken。 - 同时,配置响应拦截器以捕获401未授权响应,并触发
refreshToken的刷新流程。
- 客户端配置网络请求库(如axios)的请求拦截器,以便在发送请求时自动携带
- 检测
accessToken过期:- 响应拦截器在捕获到401未授权响应时,检查
accessToken是否已过期。 - 另一种方式是客户端主动检查
accessToken的过期时间(如通过检查令牌的到期时间字段),并在过期前使用refreshToken刷新。
- 响应拦截器在捕获到401未授权响应时,检查
- 发送刷新请求:
- 当检测到
accessToken过期时,客户端自动使用存储的refreshToken向授权服务器发送刷新请求。 - 刷新请求通常是一个POST请求,请求体中包含
refreshToken。
- 当检测到
- 接收新
accessToken:- 授权服务器验证
refreshToken的有效性,并生成一个新的accessToken(以及可能的新refreshToken)。 - 客户端接收并存储新的
accessToken(以及可能的新refreshToken)。
- 授权服务器验证
- 重新发送原始请求:
- 客户端使用新的
accessToken重新发送之前因accessToken过期而失败的请求。 - 这通常是通过拦截器自动完成的,无需用户手动干预。
- 客户端使用新的
- 处理刷新失败:
- 如果
refreshToken无效或已过期,客户端应该引导用户重新登录。 - 客户端应该能够处理刷新请求失败的情况,并给出适当的用户提示。
- 如果
- 存储
注意事项
- 安全性:
refreshToken应该具有较长的有效期,但不应无限期有效。refreshToken应该受到严格的保护,避免泄露给未经授权的第三方。- 可以在服务器端实现
refreshToken的撤销和失效机制,以提高安全性。
- 并发请求处理:
- 在多个请求同时发生时,可能只有一个请求会触发
refreshToken的刷新流程。 - 客户端需要确保在刷新
accessToken后,其他因accessToken过期而失败的请求能够使用新的accessToken重新发送。
- 在多个请求同时发生时,可能只有一个请求会触发
- 错误处理:
- 客户端应该能够处理刷新请求失败的情况,并给出适当的用户提示。
- 如果
refreshToken也无效或已过期,客户端应该引导用户重新登录。
- 存储与更新:
- 客户端应该及时更新存储的
accessToken和refreshToken,以确保它们的有效性。 - 客户端在存储这些令牌时,应该考虑使用安全的方式(如加密存储)。
- 客户端应该及时更新存储的
- 后端支持:
- 后端服务器需要提供用于刷新
accessToken的接口,并验证refreshToken的有效性。 - 后端服务器还需要在受保护资源的访问接口中验证
accessToken的有效性,并在其过期时返回相应的错误响应(如401未授权)。
- 后端服务器需要提供用于刷新
- 安全性:
示例代码
以下是一个使用axios作为网络请求库,并配置响应拦截器来实现无感刷新的示例代码:
javascriptaxios.interceptors.response.use( response => { // 对响应数据做些什么 return response; }, error => { const originalRequest = error.config; if (error.response.status === 401 && !originalRequest._retry) { // 如果状态码是401,并且没有重试过,则进行token刷新 originalRequest._retry = true; return axios.post('/refresh', { refreshToken: localStorage.getItem('refreshToken') }).then(res => { if (res.status === 200) { // 更新token localStorage.setItem('accessToken', res.data.accessToken); axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('accessToken'); // 重新发送原始请求 return axios(originalRequest); } else { // 如果刷新token失败,则引导用户重新登录 return Promise.reject(error); } }); } else { // 如果不是401错误,或者已经重试过,则直接返回错误 return Promise.reject(error); } } );
2.2 封装组件的思路
封装组件是一个将UI和逻辑分离、提高代码复用性和可维护性的过程。以下是一些封装React组件的思路:
单一职责原则
首先,明确组件的职责和功能。一个组件应该只负责一个特定的功能或界面部分,避免将多个不相关的功能或逻辑放在同一个组件中。
可重用原则
尽量设计可重用的React组件。通过抽象和提取通用的逻辑和功能,可以创建出可复用的组件,从而避免在不同的地方重复编写相同的代码。这有助于提高开发效率和代码的一致性。
设计组件的接口
确定组件的props(属性)和state(状态)。props是父组件传递给子组件的数据,而state是组件内部维护的状态。设计合理的props和state接口,使得组件易于使用和理解。
编写组件的JSX结构
根据组件的职责和功能,编写组件的JSX结构。JSX是React的语法扩展,允许在JavaScript代码中编写HTML标签。在编写JSX时,注意保持结构的清晰和简洁。
实现组件的逻辑
在组件的JSX结构中,可能需要添加一些逻辑来处理用户交互、数据更新等。这些逻辑可以放在组件的方法中,或者使用React的Hooks(如useState、useEffect等)来实现。
高内聚和低耦合
确保组件的内部逻辑和功能相互关联。不要把无关的逻辑放在同一个组件内部,这样可以提高组件的模块化和可维护性。
组件之间应该尽量减少依赖关系。避免组件之间的修改相互影响,这样可以降低系统的复杂性和提高代码的稳定性。通过合理的组件拆分和接口设计,可以实现组件之间的松耦合。
原子性原则
尽量将组件拆分成更小的原子组件。原子组件是指那些只负责单一功能或界面部分的组件,它们可以被组合成更复杂的组件。通过拆分原子组件,可以更好地复用和组合它们,从而提高开发效率和代码的可维护性。
可测试性原则
组件应该易于测试。通过合理的组件拆分和接口设计,可以创建出独立的、可测试的组件。这有助于对组件进行单元测试和集成测试,从而提高代码的质量和稳定性。
可维护性原则
拆分组件时要考虑代码的可读性和可维护性。使组件的修改和维护变得简单和可靠。通过合理的组件拆分和代码结构设计,可以降低代码的复杂性和提高代码的可读性,从而方便后续的维护和修改工作。
编写文档和注释
为组件编写文档和注释,说明其用途、props和state的接口、使用方法等。这有助于其他开发者理解和使用组件。
2.3 组件开发的第一要素
组件开发的第一要素通常是明确需求和目标。在组件开发之前,需要清晰地理解组件的功能需求、性能要求、使用场景等,这有助于确保开发出的组件能够满足实际需求并达到预期的效果。
此外,组件开发还需要考虑以下几个方面:
- 设计:组件的设计应该遵循一定的规范和标准,包括接口设计、数据结构、算法等。良好的设计可以提高组件的可维护性、可扩展性和可重用性。
- 实现:在实现组件时,需要选择合适的编程语言和工具,并编写高质量的代码。同时,还需要进行充分的测试和调试,以确保组件的稳定性和可靠性。
- 文档:编写清晰的文档对于组件的使用和维护至关重要。文档应该包括组件的功能说明、使用方法、接口说明、测试报告等。
- 团队协作:组件开发通常需要多个团队成员协作完成。因此,良好的团队协作和沟通能力也是组件开发的重要因素之一。
总之,组件开发的第一要素是明确需求和目标,同时还需要考虑设计、实现、文档和团队协作等方面。这些因素的综合考虑可以确保组件开发的顺利进行和成功完成。
2.4 如何降低组件的耦合度
降低组件间耦合度是提高代码灵活性、可维护性和可复用性的关键。以下是一些降低组件耦合度的方法:
- 单一职责原则:确保每个组件只关注单一的功能或职责,避免一个组件承担过多的责任。这样可以使组件更加独立、易于测试和修改。
- 组件通信:使用适当的组件通信方式,如 Props 和 Events,避免组件直接访问其他组件的状态。通过 Props 向子组件传递数据,通过 Events 向父组件发送消息,可以降低组件之间的耦合度。
- 抽象通用逻辑:将通用的逻辑抽象成服务、工具函数或混入(Mixin),让多个组件共享这些逻辑,避免在多个地方重复编写相同的代码。
- 解耦UI和逻辑:尽量将组件的 UI 和业务逻辑分离,使得组件更容易维护和复用。使用计算属性、监听器和组件生命周期钩子等技术来处理组件的逻辑部分。
- 使用插槽(Slot) :通过插槽机制实现组件的灵活性,让父组件可以动态地向子组件传递内容,从而降低组件之间的依赖关系。
- 依赖注入:通过依赖注入的方式将依赖关系从组件中解耦出来,使组件更加灵活和可配置。
- 接口设计:设计清晰的接口,明确定义组件之间的交互方式,避免组件之间的直接耦合,提高组件的可替换性。
2.5 声明式编程和命令式编程
2.6 媒体技术
媒体技术是指用于处理和传输媒体内容(如音频、视频、图像等)的技术。以下是一些常见的媒体技术:
- HTML5 Audio 和 Video: HTML5 提供了
<audio>和<video>元素,使网页能够直接嵌入音频和视频内容。使用这些元素,可以在网页上播放音频和视频。 - WebRTC: WebRTC(Web Real-Time Communication)是一种在网页上实现实时通信的技术。它可以用于音视频通话、视频会议、实时数据传输等。
- Canvas 和 WebGL: HTML5 的
<canvas>元素允许使用 JavaScript 绘制图形,可以用于实现复杂的动画、游戏和图形可视化。而 WebGL 则是一种基于 OpenGL ES 的 JavaScript API,可以实现高性能的 3D 图形渲染。 - SVG(Scalable Vector Graphics): SVG 是一种基于 XML 的矢量图形格式,可以用于创建可缩放的图形和动画。它在网页上可以实现各种图形效果,而且可以无损缩放。
- CSS3 Transitions 和 Animations: CSS3 提供了过渡(Transitions)和动画(Animations)功能,可以通过 CSS 定义过渡和动画效果,实现各种视觉效果。
- 媒体查询(Media Queries): 媒体查询是一种 CSS3 技术,它可以根据设备的特性(如屏幕宽度、设备类型等)来适配不同的样式和布局,从而实现响应式网页设计。
- 媒体流(Media Streams): 媒体流是一种用于获取和处理摄像头、麦克风等设备的音视频数据的技术。它可以用于 WebRTC 和实时媒体处理。
- 音频和视频编解码器: 媒体内容在传输和存储过程中需要进行编解码。常见的音频编解码器有 MP3、AAC、Ogg Vorbis 等,常见的视频编解码器有 H.264、VP9、WebM 等。
2.7 及时通信技术
及时通信技术(Real-Time Communication, RTC)是指用于实现实时数据传输和实时通信的技术。以下是一些常见的及时通信技术:
- WebRTC(Web Real-Time Communication): WebRTC 是一种开放的实时通信技术,可以在网页上实现实时音视频通话、视频会议、数据传输等功能。它使用基于浏览器的 JavaScript API,支持点对点通信和流媒体传输。
- WebSocket: WebSocket 是一种在浏览器和服务器之间建立持久性连接的技术,使双向通信成为可能。相比传统的 HTTP 请求,WebSocket 具有更低的延迟和更高的实时性,适用于实时聊天、游戏和即时数据传输等场景。
- MQTT(Message Queuing Telemetry Transport): MQTT 是一种轻量级的消息传输协议,专为物联网设备和低带宽、高延迟网络环境设计。它支持发布/订阅模式,可以实现实时数据传输和消息通知。
- Socket.IO: Socket.IO 是一个基于 WebSocket 的实时通信库,它为实时应用程序提供了跨平台、跨浏览器的通信解决方案。它支持 WebSocket、轮询和其他传输方式,以确保在各种环境中实现最佳的实时通信效果。
- SignalR: SignalR 是一个 Microsoft 开发的实时通信库,用于在客户端和服务器之间建立实时连接。它支持 WebSocket、Server-Sent Events(SSE)、长轮询等方式,为开发者提供了简单的 API 来实现实时通信功能。
- WebSockets Over HTTP/2: HTTP/2 是 HTTP 协议的最新版本,它支持多路复用和二进制传输,使 WebSocket 在 HTTP/2 上运行更加高效和稳定。
2.8 视频加密、图片加密
视频加密和图片加密是用于保护视频和图片内容安全的方法。它们涉及以下关键方面:
- 加密算法:选择合适的加密算法,如对称加密算法(如AES)和非对称加密算法(如RSA),用于对视频和图片进行加密。
- 密钥管理:生成、存储和管理加密和解密所需的密钥。密钥应该被安全地存储,仅授权的用户能够访问。
- 加密/解密过程:使用加密密钥对视频或图片进行加密,确保只有授权的用户能够解密和查看。解密过程需要正确的密钥进行解密操作。
- 数字版权管理(DRM):对于视频,数字版权管理技术可用于保护内容的合法使用,控制访问权限和防止非授权的复制和传播。
- 数字水印:数字水印技术可嵌入不可见的标识信息到视频或图片中,用于追踪和识别来源和使用情况。
2.9 md5 加密之后可以解密吗
MD5(Message Digest Algorithm 5)是一种哈希函数,它将输入数据映射为固定长度的哈希值。MD5 是单向函数,意味着它是不可逆的,无法从MD5 哈希值还原出原始数据。
因此,MD5 加密后的哈希值是不可解密的。它通常用于验证数据完整性和比对哈希值的一致性,而不是作为加密算法来加密和解密数据。
需要注意的是,由于 MD5 算法存在碰撞(collision)漏洞,即不同的输入可能会生成相同的 MD5 哈希值,因此在安全敏感的应用中,建议使用更强大和安全的哈希算法,如 SHA-256。
2.10 前端职能的质检工作
- 代码审查与规范遵循:审查和检查团队成员编写的代码,确保其符合团队的编码规范和最佳实践。强调清晰的代码结构、命名规范、注释和可维护性。
- 功能测试:确保前端页面或组件的功能性正确性。这包括检查交互、导航、表单提交、页面布局等方面的功能是否按照预期运行。
- 自动化测试和持续集成:创建并维护自动化测试套件,确保代码的持续集成和交付,以便快速检测潜在的问题。
- 跨浏览器和跨设备兼容性测试:确保前端在各种浏览器(Chrome、Firefox、Safari、Edge等)和不同设备上(移动设备、平板电脑、桌面电脑)都能正确显示和运行。
- 性能和优化检查:分析并优化前端代码,以确保页面加载速度快、性能优良。这包括减少HTTP请求、压缩资源、缓存设置等优化方面的工作。
- 可访问性测试:确保网站或应用程序对于残障人士也能够友好地访问和使用。检查颜色对比度、键盘导航、屏幕阅读器兼容性等。
- 响应式设计和布局测试:检查和确保网站或应用程序在不同尺寸和分辨率下的响应式布局效果良好。
- 页面性能分析:使用工具和技术分析页面性能指标,如加载时间、渲染时间、资源使用情况等,以便优化页面性能。
- 漏洞和安全性检查:检测并修复潜在的安全漏洞,确保前端的数据传输和处理是安全可靠的。
- 文档编写和维护:编写清晰、详细的技术文档,记录前端代码的使用方法、接口规范、配置说明等,以便于团队成员理解和使用。
2.11 什么是好的代码
好的代码是指具有良好可读性、易于理解和维护,并且具备良好的健壮性,不易出错,容易定位和修复的代码。一个代码质量高的标准通常可以归纳为两个方面:好看和好用。
- 好看: 指代码的可读性好,容易理解和维护,即使是其他人接手也不会感到困难。这包括命名规范、格式规范、日志规范等方面。一个好看的代码可以通过一些简单的原则来判断,例如良好的命名规范、简洁明了的代码结构等。
- 好用: 指代码的健壮性强,不容易出错,即使出错也容易定位和修复。好用的代码往往具有良好的逻辑清晰度、最少的依赖关系、明确的错误处理策略、高性能的设计以及避免无原则的优化等特点。
因此,要拥有高质量的代码,可以通过两种途径来实现:
- 从优秀的设计开始: 首先制定好的设计方案,然后用优秀的编码风格去实现这个设计,最后延续并保持这个优秀的编码风格。
- 不断重构: 从糟糕的代码开始,通过不断的重构逼近优秀的设计方案和编码风格,最后延续并保持这个优秀的编码风格。
在进行代码质量建设时,可以按照以下步骤进行:
- 制定规范: 首先了解什么是好的代码,制定一些简单的原则和规范,包括设计规范、编码规范和安全生产规范等。
- 实践规范: 通过一些技巧和工具,帮助我们更好地遵循规范,例如命名规范、格式规范、代码审查等。
- 度量效果: 对规范实践的效果进行度量,例如通过代码审查等方式,及时跟进和改进。
- 总结复盘: 对代码质量建设过程进行总结和复盘,及时更新规范和改进措施。
因此,好的代码质量是通过良好的设计、遵循规范、实践和度量、不断改进的过程来实现的。
2.12 项目多了如何做抽离和聚合
在面对多项目管理时,抽离和聚合是至关重要的。首先,需要明确项目目标,确保每个人都清楚他们的努力方向,以及每个工作项都对实现总目标有贡献。对于多项目管理,资源分配和进度监控是关键难点。以下是一些建议:
项目目标明确:确保团队对项目目标有共识,使用OKR等方法能够让团队思考如何共同实现总目标。这能够激发团队的主观能动性和积极性。
制定标准及流程:多项目通常涉及多团队,标准化和流程化能够减少冲突,实现团队间的默契。制定项目标准和流程,确保团队按照同一规则和标准执行任务。
微前端的思考:在拆分项目为不同子项目时,考虑微前端的方案。但要注意避免重复造轮子的问题。可以通过抽离公共组件和函数,创建一个公共项目,以实现更有效的开发。
多项目管理工具:使用适当的多项目管理工具,如PingCode和Worktile。这些工具可以协助在团队中协调和分配资源,确保最佳项目实施组合。
沟通协作:因为多项目涉及到跨团队的合作,良好的沟通协作是至关重要的。确保团队成员清晰了解其他团队的工作,促进信息流畅。
高效资源管理:核心是资源管理,确保资源分配均匀。通过合理的分工和优化进度监控,解决多项目管理中的困难。
以上建议旨在帮助你更好地抽离和聚合多项目,提高整体管理效能。
2.13 单页面和多页面的区别
SEO、资源加载、用户体验、应用性能。
3. 前端项目拓展
3.1 Monorepo
Monorepo(单一代码仓库)是一种将多个项目、库或服务存放在同一个版本控制仓库中的开发策略,与传统的每个项目单独建仓库(multirepo)形成对比。它在近年来随着前端复杂度的提升和微前端、组件库、跨项目共享等需求而变得非常流行。
对于需要高频共享代码、统一工具链、跨项目协作的前端团队来说,它是一种能显著提升开发效率和治理水平的架构模式。
什么是 Monorepo
- Monorepo:一个仓库里包含多个独立的应用程序或软件包(packages)。
- Multirepo:每个项目或包都有自己的仓库。
例如,一个公司可能有
web-app、mobile-app、shared-components、utils等多个项目,在 monorepo 模式下它们都在同一个 Git 仓库中,各自放在packages/或apps/目录下。Monorepo 的优点
优点 说明 代码共享简化 多个项目可以轻松引用同一个内部组件库或工具函数,无需发布到 npm 或复制代码。 统一依赖管理 所有项目的依赖可以提升到根目录统一安装(如使用 pnpm),避免版本冲突和重复安装。 原子提交/跨项目变更 一次提交可以同时修改多个项目(例如修改共享组件并更新所有使用它的应用),保持原子性。 一致的 CI/CD 可以编写统一的构建、测试、发布流水线,也能通过工具实现仅构建变更的项目。 简化依赖升级 更新共享库的版本时,所有项目可以立即获知,并能并行修复不兼容问题。 方便重构 IDE 的跨文件重命名、搜索等功能在整个仓库内都有效,便于大型重构。 统一工具链配置 ESLint、Prettier、TypeScript、Jest 等可以共享同一份配置文件,保持风格一致。 Monorepo 的缺点
缺点 说明 仓库体积膨胀 随着历史提交增加,仓库会变得庞大,可能影响克隆和性能(可通过 Git 稀疏检出缓解)。 权限控制复杂 难以对不同项目实现细粒度的读写权限(Git 原生不友好,需借助 CODEOWNERS、GitHub 分支保护等)。 构建性能挑战 全量构建所有包会非常慢,需要依赖增量构建、缓存、分布式计算等高级特性。 工具学习曲线 需要掌握如 Nx、Turborepo、pnpm workspace 等专门工具,团队成员需统一习惯。 容易产生紧耦合 如果缺乏良好的架构设计,项目间引用可能变得混乱,破坏边界。 主流 Monorepo 管理工具
在 JavaScript/TypeScript 生态,常用的工具分两类:包管理器的 Workspace 功能 + 构建/任务编排工具。
Workspace 功能(基础)
- npm/yarn/pnpm workspaces:提供在根目录统一安装依赖、软链接本地包的能力。其中 pnpm 效率最高(硬链接,节省磁盘空间且速度快)。
- 示例(pnpm workspaces):根目录
pnpm-workspace.yaml定义packages: - 'apps/*' - 'packages/*'。
任务编排与缓存(进阶)
这些工具解决“只构建/测试受影响的包”和“缓存结果”的问题:
工具 特点 Turborepo 增量构建 + 本地/远程缓存,配置简单,被 Vercel 广泛使用。 Nx 功能强大,支持依赖图可视化、分布式任务执行、适用于 Angular/React 等。 Lerna 老牌工具,初期用于管理多包发布,现在常与 lerna-lite+ Nx/Turbo 配合使用。Rush 微软出品,适合大型团队,提供严格的依赖策略。 Bazel 更通用(非仅 JS),适合极大规模项目,学习曲线陡峭。
4. 前端项目拓展(场景题)
4.1 如何用1分钟遍历一个100TB的文件
4.2 处理大型 JSON 文件,前端读取如何优化
当前端需要读取一个很大的 JSON 文件时,可以考虑以下几个优化方案:
- 分片加载(Chunk Loading):将大的 JSON 文件分成多个小片段,按需加载。可以使用类似于分页的方式,根据用户的操作或滚动位置来动态加载数据。这样可以避免一次性加载整个文件,提高加载速度和用户体验。
- 压缩和减小文件大小:使用压缩算法(如 Gzip 或 Brotli)对 JSON 文件进行压缩,减小文件大小,从而减少传输时间和网络带宽消耗。可以在服务器端进行压缩,然后在前端进行解压缩。
- 懒加载(Lazy Loading):只加载用户正在查看或需要的部分数据,而不是一次性加载整个 JSON 文件。例如,在滚动到某个区域时再去加载该部分的数据。这样可以避免一次性加载大量数据,提升页面加载速度。
- 使用流式处理:如果可能的话,可以将 JSON 数据转换为流式数据,并逐行或逐块进行处理,而不是一次性将整个 JSON 文件加载到内存中。这可以减少内存占用并提高处理效率。
- 使用索引或缓存:如果需要频繁地查询或操作 JSON 数据,可以考虑构建索引或使用缓存。通过索引或缓存可以加速数据的查找和操作,提升性能。
- 使用 Web Workers:将 JSON 数据读取和处理操作放到 Web Workers 中进行,以避免阻塞主线程,提高页面的响应性。
- 使用适当的数据结构:根据数据的特点和需求,选择合适的数据结构来存储和处理 JSON 数据。例如,如果需要频繁地根据某个属性进行查找,可以使用 Map 或 Set 数据结构来加快查找速度。
- 使用局部缓存:如果用户多次访问相同的 JSON 数据,可以考虑使用局部缓存来避免重复请求和加载。可以使用浏览器的缓存机制或者自定义的缓存策略。
综合使用上述优化方案,可以改善前端读取大型 JSON 文件的性能和用户体验。具体的优化策略需要根据实际情况和需求来选择和实施。
4.3 根据给定答案和作答打分的系统,如何设计
设计一个根据给定答案和作答打分的系统可以考虑以下几个步骤:
- 确定评分标准:首先,需要明确评分标准,即什么样的答案应该得到高分,什么样的答案应该得到低分。这可以是通过专家评审、历史数据或者其他方式来确定。评分标准可以是定量的(如分数范围)或者定性的(如优秀、良好、及格等级别)。
- 确定评分指标:根据评分标准,确定用于评分的具体指标。指标可以是答案的准确性、完整性、清晰度、语法正确性等。每个指标可以有不同的权重,根据重要性来决定其对总分的贡献程度。
- 提供参考答案:为了进行评分,需要提供一个或多个参考答案作为标准。这些参考答案可以是专家提供的,或者从历史数据中抽取的。参考答案可以作为标准答案与学生答案进行对比,以确定其相似度或质量。
- 匹配与对比:将学生的答案与参考答案进行匹配与对比。这可以通过文本相似度算法(如编辑距离、余弦相似度等)来实现,以确定答案的相似程度。
- 计算得分:根据匹配结果和评分指标,计算学生答案的得分。可以采用简单的加权求和或其他复杂的算法进行得分计算。
- 考虑主观因素:在设计评分系统时,还需要考虑到主观因素。有些答案可能符合评分指标,但由于表达方式不同或观点不一致,评分可能存在一定的主观性。此时,可以考虑引入专家评审或多人评分的机制来减少主观偏差。
- 测试与优化:设计好评分系统后,需要进行测试和优化。通过使用一组已知的答案和作答进行测试,验证评分结果是否符合预期。如果评分结果与预期不符,可以调整评分标准、指标权重或算法等进行优化。
需要注意的是,设计一个完善的评分系统是一个复杂的任务,其具体实现取决于应用场景和需求。以上步骤提供了一个基本的框架,可以根据实际情况进行灵活调整和扩展。
4.4 一个项目既有H5又有桌面端应用,考虑分开维护还是放在一起
将项目的H5端和桌面端应用的代码分开维护还是放在一起,取决于多种因素,包括团队规模、项目规模、开发周期、技术栈等。以下是一些考虑因素:
分开维护:
- 技术栈差异:如果H5端和桌面端应用使用了不同的技术栈或框架,分开维护可以更好地针对各自的特性进行优化和开发。
- 团队结构:如果有不同的团队负责H5端和桌面端应用的开发和维护,分开维护可以更好地分配任务和职责。
- 代码复用性:如果H5端和桌面端应用的功能和代码结构差异较大,分开维护可以避免代码冗余和混乱。
- 开发周期:如果H5端和桌面端应用的发布周期不同,分开维护可以更灵活地控制各自的发布和更新。
放在一起维护:
- 代码共享:如果H5端和桌面端应用有大量共享的业务逻辑和代码,放在一起维护可以提高代码复用性,减少重复开发和维护成本。
- 统一设计和风格:放在一起维护可以更容易保持统一的设计和风格,提高用户体验和产品一致性。
- 统一构建和部署:放在一起维护可以使用统一的构建工具和部署流程,简化开发流程和管理成本。
- 便于跨平台开发:如果有计划将应用扩展到其他平台(如移动端、平板电脑等),放在一起维护可以更容易实现跨平台开发。
在实际情况中,需要综合考虑以上因素,并根据项目的具体需求和团队的情况来决定是分开维护还是放在一起维护。无论选择哪种方式,都需要良好的代码组织和文档记录,以确保项目的可维护性和可扩展性。
4.5 项目中进行技术方案调研,难点是什么
在项目中进行技术方案调研时可能会遇到一些难点,其中一些主要难点可能包括:
- 技术选型困难: 在众多技术中选择合适的技术栈可能是一个挑战。需要考虑到项目的需求、规模、复杂度、团队技术栈熟悉度等因素,以及技术的稳定性、可维护性、扩展性等方面。
- 信息获取困难: 技术发展迅速,信息更新换代也很快,获取最新的技术信息可能需要花费大量的时间和精力。同时,需要筛选和验证信息的可靠性和适用性。
- 技术评估复杂: 对不同技术进行综合评估需要考虑多个方面的因素,如性能、安全性、成本、生态系统支持等。这需要进行详尽的测试和分析,以便做出准确的评估和决策。
- 团队技术能力匹配: 项目所选用的技术需要与团队成员的技术能力相匹配,如果技术栈过于陌生或复杂,可能会增加团队学习成本和实施难度。
- 风险评估和管理: 选择某项技术可能会带来一定的风险,如技术过时、不稳定、社区支持不足等。需要对各项技术的风险进行评估,并采取相应的风险管理措施。
- 与现有系统集成: 如果项目需要与现有系统进行集成,可能需要考虑到现有系统的技术栈、接口规范、数据格式等因素,以确保新系统与现有系统的无缝集成。
- 成本和资源限制: 技术方案的选择还需要考虑到项目的成本和资源限制,包括开发成本、运维成本、硬件资源、人力资源等方面的限制。
- 未来扩展性和可维护性: 技术方案不仅要满足当前的需求,还需要考虑到未来的扩展性和可维护性。选择具有良好扩展性和可维护性的技术方案,有助于项目长期发展。
面对这些难点,需要项目团队充分调研、分析和讨论,结合项目实际情况做出权衡和决策,以确保选择合适的技术方案来支持项目的顺利实施和长期发展。
4.6 负责的项目,用户反馈体验不友好,该如何优化
优化用户体验是一个持续改进的过程,可以通过以下几个步骤来改善项目的用户体验:
- 用户调研和反馈收集:首先,需要进行用户调研,了解用户在使用项目时所遇到的问题和不便之处。可以通过用户反馈、用户访谈、问卷调查等方式来收集用户的意见和建议,深入了解用户需求和期望。
- 分析用户痛点:根据用户调研和反馈收集的数据,分析用户的痛点和问题所在。这可能涉及到界面设计不直观、操作流程复杂、功能定位不清晰等方面的问题。通过整理用户反馈,找出共性问题和重要问题,确定优化的重点。
- 设计改进方案:针对用户反馈的问题,设计具体的改进方案。可以考虑优化界面设计、简化操作流程、改进交互方式、提供更明确的引导和帮助信息等。在设计改进方案时,需要充分考虑用户习惯和心理,以提升用户体验为目标。
- 原型验证:在实施改进之前,可以设计原型进行验证。通过设计原型,可以快速模拟用户界面和交互流程,让用户参与评审,收集用户对改进方案的意见和建议,从而及时调整和优化。
- 实施改进:根据验证结果,逐步实施改进方案。可以采用敏捷开发方式,通过迭代的方式逐步优化用户体验。在实施改进时,可以借助用户测试、A/B 测试等方式,验证改进效果,及时调整和优化。
- 持续跟踪和优化:用户体验优化是一个持续改进的过程。一旦实施了改进方案,就需要持续跟踪用户反馈和数据指标,评估改进效果,发现新的问题和机会,并持续优化用户体验。
- 用户培训和支持:除了系统本身的优化外,还可以通过用户培训和支持来提升用户体验。提供详细的使用说明、帮助文档、在线客服等支持方式,帮助用户更好地使用项目,解决问题和疑惑。
通过以上步骤,可以逐步改善项目的用户体验,提升用户满意度和使用体验。同时,需要注重持续改进,不断优化项目,以满足用户不断变化的需求。
4.7 发新版部分用户无法访问,JavaScript 加载报错
- 打包 dist --> 增量上传 --> CDN 静态资源服务器。(要做增量发布,不做全量发布)
- 常规 nginx 配置 html 不做缓存。