《前端60问:从设备判断到性能优化全解》
1. 如何判断用户设备?
通过浏览器提供的 navigator.userAgent
字符串,可以知道用户用的是手机还是电脑,甚至是哪个系统(iOS、Android、Windows)。只要查找里面是否包含“Android”、“iPhone”、“Windows”等关键词,就能判断设备类型。
2. 如何将多次提交压缩成一次提交?
假如用户快速连续点击提交按钮,我们不想每次都发送请求,可以用“防抖(debounce)”或“节流(throttle)”技术。
防抖:等用户停止操作一段时间后才触发一次。
节流:限制一段时间内只能触发一次,间隔时间内重复操作会被忽略。
3. 介绍下 navigator.sendBeacon 方法
navigator.sendBeacon
用来异步发送数据,适合页面关闭或跳转时上传日志或埋点。它不会阻塞页面关闭,保证数据能发送出去而不影响用户体验。
4. 混动跟随导航(电梯导航)该如何实现?
页面内容有多个板块,左侧导航栏会根据滚动位置自动高亮当前板块,用户点击导航则滚动到对应内容。
实现思路是监听滚动事件,根据当前滚动条位置判断显示哪个导航项高亮。
5. 退出浏览器之前发送积压埋点数据请求如何做?
页面关闭或跳转时,常用 beforeunload
或 visibilitychange
事件触发,结合 navigator.sendBeacon
发送未发送完的埋点数据,保证数据可靠上传且不阻塞关闭动作。
6. 如何统计页面的 long task(长任务)?
浏览器性能监控中,长任务是指占用主线程超过50毫秒的任务。用 PerformanceObserver
监听 longtask
类型事件,就能捕获这些耗时操作,帮助定位卡顿问题。
7. PerformanceObserver 如何测量页面性能?
PerformanceObserver
是浏览器提供的接口,可以监听各种性能指标事件,比如资源加载、长任务、首次绘制等,实时获取性能数据,用于性能分析和优化。
8. 移动端如何实现下拉滚动加载(顶部加载)?
监听用户滚动或下拉手势,当滚动到页面顶部且用户继续下拉时,触发数据刷新或加载更多。一般结合触摸事件和滚动事件做判断。
9. 判断页签是否为活跃状态?
用浏览器的 Page Visibility API,监听 document.visibilityState
属性和 visibilitychange
事件。当页面切换到后台,状态变为 hidden
,回到前台时为 visible
。
10. 网络带宽一定时,切片上传和整体上传时间差不多吗?
不一定。切片上传可以分块并发上传,支持断点续传,理论上更快;但每个请求会有额外开销,如果切片过多可能导致整体耗时增加。
11. 大文件切片上传确定切片数量时有哪些考量因素?
单片大小不能太大,避免网络卡顿
不能太小,避免请求数量过多
根据用户网络速度和服务器负载调整
浏览器内存限制和上传稳定性也是考虑因素
12. 页面关闭时执行方法该如何做?
监听浏览器的 beforeunload
或 unload
事件,在里面用 navigator.sendBeacon
发送数据。sendBeacon
是唯一不会阻塞关闭且可靠的发送方式。
13. 如何统计用户 PV 访问的发起请求数量?
在所有网络请求发起点(如 XMLHttpRequest
、fetch
)处增加拦截统计,记录每个请求发起次数。结合后端日志分析访问量。
14. 长文本溢出,展开/收起如何实现?
用 CSS 属性 overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
实现省略号效果。配合按钮切换状态,控制文本显示完整或溢出。
15. 如何实现鼠标拖拽?
监听元素的 mousedown
事件记录起始位置,监听 mousemove
事件动态修改元素位置,mouseup
停止拖拽。
16. 统计全站每一个静态资源加载耗时,该如何做?
使用浏览器 Performance API
中的 performance.getEntriesByType('resource')
获取所有资源的加载时间和详细信息。
17. 防止前端页面重复请求?
在发起请求前检查是否有相同请求正在进行,可以用请求缓存或用 AbortController
取消重复请求。
18. ResizeObserver 作用是什么?
监听某个 DOM 元素大小变化,实时做出响应,如调整布局或重新计算尺寸。
19. 要实时统计用户浏览器窗口大小,该如何做?
监听 window
的 resize
事件,每次触发时读取 window.innerWidth
和 window.innerHeight
即可。
20. 当项目报错想定位哪个 commit 引入的错误该怎么做?
用 Git 自带的二分查找命令 git bisect
,自动帮助你定位哪个提交引入了错误。
21. 如何移除一个指定的 commit?
可以用 git revert <commit>
撤销该次提交,或者用 git reset
回退到之前某个版本。
22. 如何还原用户操作流程?
通过前端埋点记录用户操作事件和参数,结合行为回放工具,将用户操作顺序和状态还原。
23. 是否能将请求调用源码地址和代码行数上报?
可以,通过捕获错误堆栈(stack trace)和上传 sourcemap 文件,定位源码文件和代码行号。
24. 请求失败弹多个 toast,如何只弹一个?
用状态锁或节流机制控制,只允许一个错误提示弹窗显示,后续错误忽略或合并提示。
25. 如何减少项目里面 if-else?
用设计模式(策略模式)、映射表或者多态,避免大量嵌套的条件判断。
26. babel-runtime 作用是啥?
它包含 Babel 编译后依赖的辅助函数和 polyfill,避免同样代码在多个文件重复出现,减小代码体积。
27. 如何实现预览 PDF 文件?
用开源库 PDF.js 直接在浏览器渲染,或者用 <iframe>
、<embed>
嵌入浏览器自带 PDF 阅读器。
28. 如何在划词选择文本上添加右键菜单?
监听 mouseup
事件判断是否有选中文本,结合 contextmenu
事件显示自定义菜单。
29. 富文本如何做到划词?
利用 Selection API 获取用户选中的文本范围,再做相应操作,比如添加样式或弹菜单。
30. 如何做好前端监控方案?
覆盖性能监控、错误监控、用户行为监控,结合数据上报、日志分析和告警机制。
31. 如何标准化处理线上用户反馈的问题?
统一收集渠道,自动化归类和标签,关联日志和用户环境,快速响应并回馈处理结果。
32. px 如何转为 rem?
按设计稿基准字体大小计算,比如设计稿宽度除以根字体大小,转换 px 为 rem。
33. 浏览器同源策略下 CDN 请求为何不受限?
CDN 通常配置了 CORS 跨域资源共享,允许其他域访问资源。
34. cookie 可以实现不同域共享吗?
不可以,cookie 只能在相同域或子域间共享。
35. axios 是否可以取消请求?
可以,使用 Axios 提供的 CancelToken 或浏览器的 AbortController 取消请求。
36. 前端如何实现折叠面板效果?
用状态控制内容显示隐藏,配合 CSS 过渡动画实现平滑展开收起。
37. DOM 里面,如何判定 a 是 b 的子元素?
用 b.contains(a)
判断,返回 true 表示是子元素。
38. 判断对象是否为空,包括原型链上的自定义数据或方法如何判定?
递归检查对象本身和其原型链上的所有属性,确认是否有自定义数据或方法。
39. is 如何判空?(空数组、空对象、空字符串、0、undefined、null、空 Map、空 Set)
分别判断:数组长度为0,对象无自有属性,字符串空字符,数字0视业务决定,null 和 undefined 直接判空,Map 和 Set 大小为0。
40. CSS 实现翻牌效果?
用 CSS3 3D 变换属性 transform-style: preserve-3d
,结合 rotateY(180deg)
实现翻转动画。
41. flex:1 代表什么?
表示元素在弹性容器内可增长,占据剩余空间,且基础大小为0。
42. 一般怎么做代码重构?
重构时拆分大函数,清理重复代码,重命名不明确变量,提高代码可读性和维护性。
43. 如何清理源码里没被应用的 JS、TS、CSS 代码?
用 Chrome DevTools Coverage 工具检测未使用代码,结合构建工具(Webpack、Rollup)进行 Tree Shaking。
44. 前端应用如何做国际化?
用国际化库(如 i18next、vue-i18n),管理不同语言的文本资源,动态切换语言。
45. 应用如何做应用灰度发布?
通过配置中心或用户分组,控制部分用户访问新版本,逐步推广,降低风险。
46. 微前端为何通常不选 iframe 方案?
iframe 隔离过强,通信困难,且不易统一样式和路由管理。
47. Qiankun 是如何做 JS 隔离的?
使用沙箱技术,劫持全局变量和方法,实现子应用的独立运行环境。
48. 微前端架构一般如何做 JS 隔离?
用沙箱(Proxy、iframe、vm2等)技术隔离各子应用的全局作用域。
49. React 循环渲染中为什么推荐不用 index 做 key?
index 会因元素顺序变化导致组件复用错误,影响渲染性能和状态。
50. React 如何避免 context 引起整个挂载节点树重新渲染?
拆分多个 context,配合 React.memo
或第三方 useContextSelector
精细控制更新。
51. 前端如何实现截图?
用 html2canvas 或 Canvas API,把页面 DOM 转成图片。
52. 当 QPS 达到峰值时如何处理?
限流、降级服务、增加缓存、负载均衡和自动弹性伸缩。
53. JS 超过 Number 最大值的数怎么处理?
使用 BigInt
类型或者第三方大数库处理超大数字。
54. 使用同一个链接,如何实现 PC 打开是 web 应用,手机打开是 H5 应用?
服务器根据 User-Agent 判断设备类型,重定向到对应页面。
55. 如何保证用户的使用体验?
保证页面响应快、界面简洁、操作流畅、错误容错和合理交互反馈。
56. 如何解决页面请求接口大规模并发问题?
请求合并、缓存、限流和排队处理,减轻服务器压力。
57. 设计一套全站请求耗时统计工具?
拦截所有请求,记录请求发起和完成时间,分析平均耗时和异常。
58. 大文件上传了解多少?
了解切片上传、断点续传、并发上传、错误重试等技术。
59. H5 如何解决移动端适配问题?
用弹性布局、媒体查询、rem 单位和视口设置适配多屏。
60. 站点一键换肤的实现方式有哪些?
动态修改 CSS 变量,加载不同主题样式文件或使用预处理器变量替换。