当前位置:首页 » 《资源分享》 » 正文

2024年前端最新场景题面试攻略(七)

18 人参与  2024年12月23日 14:00  分类 : 《资源分享》  评论

点击全文阅读


61. 在表单校验场景中, 如何实现⻚⾯视⼝滚动到报错的位置 【热度: 248】 基本原理 ⻚⾯是⽤⼾与程序进⾏交互的界⾯,在对应表单校验场景中,通常会因为有填写错误需要⽤⼾进⾏修改。为了提⾼⽤⼾体验,可以将⻚⾯滚动⾄对应表单报错的位置,使得⽤⼾⽴即可⻅错误并进⾏修改。这通常可以通过 JavaScript 编程实现。 要注意的是,实现滚动⾄错误表单,⼀般需要⼏个步骤: 1. 记录表单元素的位置:在表单提交前的适当时间⾥记录所有表单元素的错误位置。 2. 滚动到特定错误:错误发⽣时,滚动到第⼀个错误的表单元素位置。 3. 优化:可为同⼀元素多次错误滚动优化,避免不必要的⽤⼾⼲扰。 以下是这些步骤的代码⽰例 HTML:
1 <form id="myForm" onsubmit="return false;"<input type="text" id="name"name="name" /><input type="text" id="age" name="age" /><!-- ... 其他表单元素 ...--><button type="submit" onclick="handleValidation()"Submit</button</form
JavaScript:
1 // ⼀个假设的表单验证函数function validateInput(inputId) {// 调⽤此处的校验逻辑,返回是否存在错误// 这⾥以ID "inputId"来获取对应的DOM对象var el =document.getElementById(inputId);// 此处只是⽰例, 实际上应根据具体的校验逻辑返回⼀个布尔类型return el.value === "预期值";2 }34 function handleValidation() {var valid = true;5 ["name", "age"].forEach((key) => {// 进⾏校验判断if (!validateInput(key)){console.error(`Validation failed for: ${key}`);6 // 标记校验失败7 valid = false;8 // 滚动到出现问题的元素位置var element = document.getElementById(key);9 element.scrollIntoView({ block: "center", behavior: "smooth" });10 // 增加⼀些提⽰效果, ⽐如错误边框, 可按需实现// element.classList.add('errorhighlight');11 }12 });13 // 检查是否验证失败,如果失败则不提交表单return valid;14 }1516 // 处理表单提交事件,与HTML中的onclick绑定document.getElementById("myForm").addEventListener("submit", (e) => {17 e.preventDefault(); // 阻⽌表单默认提交⾏为18 handleValidation();19 });
62. 如何⼀次性渲染⼗万条数据还能保证⻚⾯不卡顿【热度: 426】 原理其实就是 通过 requestAnimationFrame 实现分块⼉加载。 requestAnimationFrame + fragment(时间分⽚) 既然定时器的执⾏时间和浏览器的刷新率不⼀致,那么我就可以⽤ requestAnimationFrame 来解 决requestAnimationFrame 也是个定时器,不同于 setTimeout ,它的时间不需要我们⼈为指 定,这个时间取决于当前电脑的刷新率,如果是 60Hz ,那么就是 16.7ms 执⾏⼀次,如果是 120Hz 那就是 8.3ms 执⾏⼀次 因此 requestAnimationFrame 也是个宏任务,前阵⼦⾯试就被问到过这个 这么⼀来,每次电脑屏幕 16.7ms 后刷新⼀下,定时器就会产⽣ 20 个 li , dom 结构的出现和屏幕 的刷新保持了⼀致
1 const total = 100000;2 let ul = document.getElementById("container");3 let once = 20;4 let page = total / once;56 function loop(curTotal) {if (curTotal <= 0) return;7 let pageCount = Math.min(curTotal, once);8 window.requestAnimationFrame(() => {for (let i = 0; i < pageCount; i++) {letli = document.createElement("li");9 li.innerHTML = ~~(Math.random() * total);10 ul.appendChild(li);11 }12 loop(curTotal - pageCount);13 });14 }15 loop(total);
其实⽬前这个代码还可以优化⼀下,每⼀次 appendChild 都是新增⼀个新的 li ,也就意味着需要 回流⼀次,总共⼗万条数据就需要回流⼗万次 此前讲回流的时候提出过虚拟⽚段 fragment 来解决这个问题 fragment 是虚拟⽂档碎⽚,我们⼀次 for 循环产⽣ 20 个 li 的过程中可以全部把真实 dom 挂载 到 fragment 上,然后再把 fragment 挂载到真实 dom 上,这样原来需要回流⼗万次,现在只需 要回流 100000 / 20 次
1 const total = 100000;2 let ul = document.getElementById("container");3 let once = 20;4 let page = total / once;56 function loop(curTotal) {if (curTotal <= 0) return;7 let pageCount = Math.min(curTotal, once);8 window.requestAnimationFrame(() => {let fragment =document.createDocumentFragment(); // 创建⼀个虚拟⽂档碎⽚for (let i = 0; i <pageCount; i++) {let li = document.createElement("li");9 li.innerHTML = ~~(Math.random() * total);10 fragment.appendChild(li); // 挂到fragment上11 }12 ul.appendChild(fragment); // 现在才回流13 loop(curTotal - pageCount);14 });15 }16 loop(total);
进阶: 如果做到极致的话, 可以考虑通过动态计算渲染的量, ⼀次性渲染多少。 63. [webpack] 打包时 hash 码是如何⽣成的【热度: 167】 Webpack 在打包过程中⽣成 hash 码主要⽤于缓存和版本管理。主要有三种类型的 hash 码: 1. hash:是和整个项⽬的构建相关,只要项⽬⽂件有修改,整个项⽬构建的 hash 值就会更改。这意味着任何⼀个⽂件的改动都会影响到整体的 hash 值。 2. chunkhash:与 webpack 打包的 chunk 有关,不同的 entry 会⽣成不同的 chunkhash 值。例 如,如果你的配置⽣成了多个 chunk(例如使⽤了 code splitting),每个 chunk 的更新只会影响 到它⾃⾝的 chunkhash。 3. contenthash:根据⽂件内容来定义 hash,内容不变,则 contenthash 不变。这在使⽤诸如 CSS提取到单独⽂件的插件时特别有⽤,因此只有当⽂件的内容实际改变时,浏览器才会重新下载⽂件。 ⽣成⽅式: • hash 和 chunkhash 主要是通过某种 hash 算法(默认 MD5)来对⽂件名或者 chunk 数据进⾏编 码。 • contenthash 是通过构建时的 webpack 插件(如 mini-css-extract-plugin)来处理的,它会对⽂ 件内容进⾏ hash。 Hash 码的⽣成可以被 webpack 配置的 hashFunction,hashDigest,hashDigestLength 等选项影 响。例如,你可以选择不同的算法如 SHA256 或者 MD5,以及可以决定 hash 值的⻓度。 在 webpack 的配置⽂件中,可以通过如下⽅式设定 hash: 这会将输出的⽂件名设置为⼊⼝名称加上基于每个 chunk 内容的 hash。在使⽤ webpack-dev server 或者 webpack --watch 时,不会⽣成实际的⽂件,所以这些 hash 值是在内存中计算并 关联的。 64. 如何从 0 到 1 搭建前端基建【热度: 404】 如何从 0 到 1 搭建前端基建 有⼀个⾮常经典的⽂章, 直接参考即可: ⾮⼤⼚的我们,要如何去搞前端基建? 这⾥简单总结⼀下⽂章⾥⾯的要点 1.什么是基建? 2.为什么要做前端基建? 业务复⽤; 提升研发效率; 规范研发流程; 团队技术提升; 团队的技术影响⼒; 开源建设; 3.前端基建如何推动落地? • 要合适的同学(资源) • 要解决的问题(问题) • 要解决问题⽅案计划书(⽅案) • 要具体执⾏的步骤(执⾏) 技术基建四⼤特性(切记) • 技术的健全性 • 基建的稳定性 • 研发的效率性 • 业务的体验性 4.前端基建都有什么? • 前端规范(Standard) • 前端⽂档(Document) • 前端项⽬模板管理(Templates) • 前端脚⼿架(CLI) • 前端组件库(UI Design) • 前端响应式设计 or ⾃适应设计 • 前端⼯具库(类 Hooks / Utils) • 前端⼯具⾃动化(Tools) • 接⼝数据聚合(BFF) • 前端 SSR 推进 • 前端⾃动化构建部署(CI/CD) • 全链路前端监控/数据埋点系统 • 前端可视化平台 • 前端性能优化 • 前端低代码平台搭建 • 微前端(Micro App) 65. 你在开发过程中, 使⽤过哪些 TS 的特性或者能⼒?【热度: 670】 直接上⼲货: 1. Utility Types(⼯具类型): ◦ Partial<T>: 将类型 T 的所有属性变为可选。 ◦ Required<T>: 将类型 T 的所有属性变为必选。 ◦ Readonly<T>: 将类型 T 的所有属性变为只读。 ◦ Record<K, T>: 创建⼀个具有指定键类型 K 和值类型 T 的新对象类型。 ◦ Pick<T, K>: 从类型 T 中选择指定属性 K 形成新类型。 ◦ Omit<T, K>: 从类型 T 中排除指定属性 K 形成新类型。 ◦ Exclude<T, U>: 从类型 T 中排除可以赋值给类型 U 的类型。 ◦ Extract<T, U>: 从类型 T 中提取可以赋值给类型 U 的类型。 ◦ NonNullable<T>: 从类型 T 中排除 null 和 undefined 类型。 ◦ ReturnType<T>: 获取函数类型 T 的返回类型。 ◦ Parameters<T>: 获取函数类型 T 的参数类型组成的元组类型。 2. 条件判定类型: ◦ Conditional Types(条件类型): 根据类型关系进⾏条件判断⽣成不同的类型。 ◦ Distribute Conditional Types(分布式条件类型): 分发条件类型,允许条件类型在联合类型上 进⾏分发。 3. Mapped Types(映射类型):根据已有类型创建新类型,通过映射类型可以⽣成新的类型结构。 4. Template Literal Types(模板⽂字类型):使⽤字符串模板创建新类型。 5. 类型推断关键字: ◦ keyof 关键字:关键字允许在泛型条件类型中推断类型变量。 ◦ instanceof:运算符⽤于检查对象是否是特定类的实例。 ◦ in:⽤于检查对象是否具有特定属性。 ◦ type guards:类型守卫是⾃定义的函数或条件语句,⽤于在代码块内缩⼩变量的类型范围。 ◦ as:⽤于类型断⾔,允许将⼀个变量断⾔为特定的类型。 66. JS 的加载会阻塞浏览器渲染吗?【热度: 243】 JavaScript 的加载、解析和执⾏默认情况下会阻塞浏览器的渲染过程。这是因为浏览器渲染引擎和 JavaScript 引擎是单线程的,并且⼆者共享同⼀个线程。JavaScript 在执⾏时会阻⽌ DOM 构建,因为 JavaScript 可能会修改 DOM 结构(例如添加、修改或删除节点)。出于这个原因,浏览器必须暂停 DOM 的解析和渲染,直到 JavaScript 执⾏完成。 默认情况下,当浏览器遇到⼀个 <script> 标签时,会⽴即停⽌解析 HTML,转⽽下载和执⾏脚本, 然后再继续 HTML 的解析和渲染。这意味着在 HTML ⽂档中的 JavaScript 脚本的下载和执⾏过程中,⻚⾯的渲染是被阻塞的。 不过,你可以⽤下⾯⼏种⽅法调整脚本的加载和执⾏⾏为,以减少对浏览器渲染过程的阻塞: 1. 异步脚本(async): 在 <script> 标签中使⽤ async 属性可以使得脚本的加载变成异步操作。当使⽤ async 属性 时,浏览器会在后台进⾏下载,但脚本的执⾏还是会阻塞 DOM 渲染。
1 <script async src="script.js"</script
1. 使⽤ async 时,脚本会在下载完成后尽快执⾏,这可能会在⽂档解析完成之前或之后。 2. 延迟脚本(defer): defer 属性使得脚本在 HTML 解析完成之后、DOMContentLoaded 事件触发之前执⾏,不阻塞 HTML 的解析。
1 <script defer src="script.js"</script

 1. 使⽤ defer ,脚本的执⾏顺序将按照它们在 DOM 中出现的顺序执⾏。

2. 动态脚本加载: 你可以使⽤ JavaScript 动态创建 <script> 元素并添加到 DOM 中,这允许你控制脚本的加载和 执⾏时机。
1 var script = document.createElement("script");2 script.src = "script.js";3 document.body.appendChild(script);
1. 移动脚本位置: 将脚本放在 HTML 的底部,即 <body> 标签关闭之前,⽽不是放在 <head> 中,可以让⻚⾯内容 先加载显⽰,从⽽减少⽤⼾对加载过程的可感知时间。 现代 Web 开发中通常推荐使⽤ async 或 defer 属性,提⾼⻚⾯加载性能,尤其是对于那些需要从外部服务器加载的⼤型 JavaScript 库来说尤为关键。 67. 浏览器对队头阻塞有什么优化?【热度: 368】 队头阻塞(Head-of-Line Blocking,缩写 HoLB)问题主要发⽣在⽹络通信中,特别是在使⽤ HTTP/1.1 和以前版本时,在⼀个 TCP 连接中同⼀时间只能处理⼀个请求。即使后续的请求已经准备好在客⼾端,它们也必须等待当前处理中的请求完成后才能被发送。这会延迟整个⻚⾯或应⽤的⽹络请求,降低性能。 现代浏览器和协议已经实施了多种优化措施来减少或解决队头阻塞问题: 1. HTTP/2: 为了解决 HTTP/1.x 的诸多问题,包括队头阻塞问题,HTTP/2 引⼊了多路复⽤(multiplexing)功 能。这允许在同⼀ TCP 连接上同时传输多个独⽴的请求-响应消息。与 HTTP/1.1 相⽐,HTTP/2 在同⼀个连接上可以并⾏处理多个请求,⼤⼤减少了队头阻塞的问题。 2. 服务器推送: HTTP/2 还引⼊了服务器推送(server push)功能,允许服务器主动发送多个响应到客⼾端,⽽不 需要客⼾端明确地为每个资源提出请求。这提⾼了⻚⾯加载的速度,因为相关资源可以被预先发送 ⽽⽆需等待浏览器请求。 3. 域名分散(Domain Sharding): 这种技术常⽤于 HTTP/1.1 中,通过创建多个⼦域,使得浏览器可以同时开启更多的 TCP 连接来加载资源。虽然这种⽅法可以在⼀定程度上减轻队头阻塞,但它增加了复杂性,并且在 HTTP/2 中由于多路复⽤功能变得不再必要。 4. 连接重⽤(Connection Reuse): 这是 HTTP/1.1 中的⼀个特性,即持久连接(Persistent Connections),允许在⼀次 TCP 连接中 发送和接收多个 HTTP 请求和响应,⽽⽆需开启新的连接,从⽽减少了 TCP 握⼿的开销并提升了效率。 5. 资源优化: 减少资源的⼤⼩通过压缩(如 GZIP),优化图⽚,减少 CSS 和 JavaScript ⽂件的⼤⼩等,可以减少队头阻塞的影响,因为⼩资源⽂件传输更快。 6. 优先级设置: HTTP/2 允许设置资源的加载优先级,使得关键资源(如 HTML,CSS,JavaScript)可以⽐不那么重要的资源(如图⽚,⼴告)更早加载。 7. 预加载: 浏览器可以通过使⽤ <link rel="preload"> 标签预加载关键资源,例如字体⽂件和关键脚 本,这样可以确保它们在主要内容加载之前已经准备好。 8. HTTP/3 和 QUIC 协议: HTTP/3 是未来的推进⽅向,它基于 QUIC 协议,⼀个在 UDP 之上的新传输层协议,旨在进⼀步减少延迟,解决 TCP/IP 协议的队头阻塞问题。 总的来说,HTTP/2 的特性如多路复⽤、服务器推送和优先级设置都有助于减少队头阻塞。⽽ HTTP/3的引⼊可能会在未来为⽹络通信带来根本性的变化。在使⽤ HTTP/2、HTTP/3 和浏览器级别的优化时,⽹⻚开发者也需注意资源加载优化的最佳实践,以更全⾯地应对队头阻塞问题。 68. Webpack 项⽬中通过 script 标签引⼊资源,在项⽬中如何处理?【热度: 100】 在使⽤ Webpack 打包的项⽬中,通常资源(如 JavaScript、CSS、图⽚等)会被 Webpack 处理,因为 Webpack 的设计初衷就是将所有资源视为模块,并进⾏有效的管理和打包。但有时候可能需要通过 <script> 标签直接引⼊资源,这通常有两种情况: 1. 在 HTML ⽂件中直接引⼊: 可以在项⽬的 HTML ⽂件中直接使⽤ <script> 标签来引⼊外部资源: 1. 这种⽅法简单直接,但要记住,由于这些资源不会被 Webpack 处理,它们不会被包含在 Webpack 的依赖图中,并且也不会享受到 Webpack 的各种优化。 2. 使⽤ Webpack 管理: 如果想要 Webpack 来处理这些通过 <script> 引⼊的资源,可以使⽤⼏种插件和加载器: ◦ html-webpack-plugin 可以帮助你⽣成⼀个 HTML ⽂件,并在⽂件中⾃动引⼊ Webpack 打包后的 bundles。 ◦ externals 配置允许你将⼀些依赖排除在 Webpack 打包之外,但还是可以通过 require 或 import 引⽤它们。 ◦ script-loader 可以将第三⽅全局变量注⼊的库当作模块来加载使⽤。 3. 例如,使⽤ html-webpack-plugin 和 externals ,你可以将⼀个库配置为 external,然后 通过 html-webpack-plugin 将其引⼊:

 1. 然后,在你的 index.html 模板⽂件中可以这样引⼊资源:

1 <script src="https://cdn.example.com/library.js"</script
1. 使⽤ externals 的⽅法能让你在 Webpack 打包的模块代码中⽤正常的 import 或 require 语句来引⽤那个全局变量:
1 // 你的 JavaScript 代码⽂件中import Library from "libraryName"; // 虽然定义了external,Webpack依然会处理这个import
应根据项⽬需求和现有的架构来决定使⽤哪种⽅法。上述两种⽅法中,第⼆种可以更好地利⽤ Webpack 的功能,第⼀种则更加简单直接。 69. 应⽤上线后, 怎么通知⽤⼾刷新当前⻚⾯?【热度: 466】 ⾸先第⼀个问题 ⽤⼾在没有⻚⾯刷新的情况下, 如何去感知前端静态资源已经发⽣了更新? ⾸先要做静态资源版本管理。 这个版本直接给到 html 模板即可, 其他 link 打包的资源还是以哈希 code 作为⽂件名称后缀。 就类似于这样⼦的
1 xxx.1.0.0.html --> vender.hash_1.js、 vender.hash_2.js、 vender.hash_3.js、vender.hash_1.css2 xxx.1.0.1.html --> vender.hash_a.js、 vender.hash_b.js、 vender.hash_c.js、vender.hash_d.css
如何主动推送给客⼾端 这个实现⽅式就⾮常的多了,我这⾥建议让服务端来做处理 因为我们前端静态资源打包之后, ⼤多数会上传到云存储服务器上, 或者甚⾄是 服务器本地 也⾏。 这个时候, 后端给⼀个定时任务, ⽐如 1 分钟去执⾏⼀次, 看看是否有新的 html 版本的内容⽣成。 如果有新的 html 版本内容⽣成, 且当前⽤⼾访问的还是旧版本, 那么直接发⼀个服务端信息推送即可(SSE 允许服务器推送数据到浏览器)。 这样做成本是最低的, 甚⾄可以说是⼀劳永逸。 前端是没有任何负债, 没有任何性能问题。 那是否还有别的处理⽅式呢? 当然是有的。 1. WebSockets: 通过 WebSocket 连接,服务器可以实时地向客⼾端发送消息,包括静态资源更新的通知。收到消息后,客⼾端可以采取相应的措施,⽐如显⽰⼀个提⽰信息让⽤⼾选择是否重新加载⻚⾯。 1. Service Workers(推荐): Service workers 位于浏览器和⽹络之间,可以控制⻚⾯的资源缓存。它们也可⽤于检测资源更新,当检测到静态资源更新时,可以通过推送通知或在⽹站上显⽰更新提⽰。 1. 轮询: 客⼾端⽤ JavaScript 定时发送 HTTP 请求到服务器,查询版本信息。如果检测到新版本,可以提醒⽤⼾或⾃动刷新资源。 在绝⼤多数情况下,使⽤ Service Workers 可能是最稳妥的做法,因为它不仅提供了资源缓存和管理的能⼒,⽽且也可以在后台做资源更新的检查,即使⽤⼾没有开启⽹⻚也能实现通知和更新的功能。 当然,选择哪种⽅案还需考虑应⽤的需求、⽤⼾体验和实现复杂度等因素。 70. Eslint 代码检查的过程是啥?【热度: 111】 ESLint 是⼀个插件化的静态代码分析⼯具,⽤于识别 JavaScript 代码中的问题。它在代码质量和编码 ⻛格⽅⾯有助于保持⼀致性。代码检查的过程通常如下: 1. 配置: ⾸先需要为 ESLint 提供⼀套规则,这些规则可以在 .eslintrc 配置⽂件中定义,或者在项⽬的 package.json ⽂件中的 eslintConfig 字段⾥指定。规则可以继承⾃⼀套已有的规则集, 如 eslint:recommended ,或者可以是⼀个流⾏的样式指南,如 airbnb 。也可以是⾃定义 的规则集。 2. 解析: 当运⾏ ESLint 时,它会使⽤⼀个解析器(如 espree ,默认的解析器)来解析代码,将代码转换 成⼀个抽象语法树(AST)。AST 是代码结构的⼀个树状表⽰,能让 ESLint 理解代码的语义结构。 3. 遍历: ⼀旦代码被转换成 AST,ESLint 则会遍历该树。它会查找树的每个节点,检查是否有任何规则适⽤于该节点。在遍历过程中,如果发现违反了某项规则,ESLint 将记录⼀个问题(通常称为“lint 错 误”)。 4. 报告: 在遍历完整个 AST 之后,ESLint 会⽣成⼀份报告。这份报告详细说明了它在代码中找到的任何问 题。这些问题会被分类为错误或警告,根据配置设置的不同,某些问题可能会阻⽌构建过程或者被 忽略。 5. 修复: 对于某些类型的问题,ESLint 提供了⾃动修复的功能。这意味着你可以让 ESLint 尝试⾃动修复它 所发现的问题,不需⼈⼯⼲预。 6. 集成: ESLint 可以集成到 IDE 中,这样就可以在代码编写过程中即时提供反馈。它也可以被集成到构建⼯具如 Webpack 或任务运⾏器 Grunt、Gulp 中,作为构建过程或提交代码到版本控制系统前的⼀个步骤。 通过以上步骤,ESLint 帮助开发者在编码过程中遵循⼀致的⻛格和避免出现潜在的错误。  更多前端面试资料无常分享 【点击领取】

点击全文阅读


本文链接:http://zhangshiyu.com/post/205695.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1