高新网站开发多少钱,破解网站后台账号密码,上海响应式网站建设,电商网站支付接口87.场景面试之大数运算#xff1a;超过js中number最大值的数怎么处理
在 JavaScript 中#xff0c;Number.MAX_SAFE_INTEGER#xff08;即 2^53 - 1#xff0c;即 9007199254740991#xff09;是能被安全表示的最大整数。超过此值时#xff0c;普通的 Number 类型会出现…87.场景面试之大数运算超过js中number最大值的数怎么处理
在 JavaScript 中Number.MAX_SAFE_INTEGER即 2^53 - 1即 9007199254740991是能被安全表示的最大整数。超过此值时普通的 Number 类型会出现精度丢失问题导致运算结果不准确。 如何处理大数运算
JavaScript 提供了几种处理大数的方法
1. 使用 BigIntES11 引入适用于整数运算
BigInt 是 JavaScript 原生支持的大整数类型适用于超过 Number.MAX_SAFE_INTEGER 的整数运算。
const bigNum1 BigInt(9007199254740991000000);
const bigNum2 BigInt(123456789123456789);console.log(bigNum1 bigNum2); // 9007199378197780123456n
console.log(bigNum1 * bigNum2); // 正确计算超大数相乘注意
BigInt 不能与 Number 直接混合运算必须转换。Math 库不支持 BigInt例如 Math.sqrt(BigInt(16)) 会报错。 2. 使用 big.js、bignumber.js、decimal.js 等第三方库适用于小数运算
BigInt 只适用于整数对于大浮点数运算可以使用 bignumber.js 这样的库
import BigNumber from bignumber.js;const num1 new BigNumber(9007199254740991000000);
const num2 new BigNumber(123456789.123456789);console.log(num1.plus(num2).toString()); // 精确计算大数加法
console.log(num1.times(num2).toString()); // 精确计算大数乘法优势
适用于浮点数运算避免 JavaScript 内置 Number 的精度问题。计算结果可以转换为字符串避免 BigInt 只支持整数的问题。 3. 使用字符串手写大数运算适用于特定场景
如果第三方库不适用也可以手写字符串处理大数
function addBigNumbers(a, b) {let res ;let carry 0;let i a.length - 1, j b.length - 1;while (i 0 || j 0 || carry) {let sum (i 0 ? a[i] : 0) (j 0 ? b[j] : 0) carry;carry Math.floor(sum / 10);res (sum % 10) res;i--; j--;}return res;
}console.log(addBigNumbers(9007199254740991, 123456789123456789));
// 输出: 132463988378197780适用场景
仅涉及加法、乘法等基本运算。不想引入 BigInt 或外部库。 总结
方案适用场景优势限制BigInt超大整数运算内置支持性能好仅支持整数无法处理小数big.js / bignumber.js超大整数 浮点数运算兼容小数计算API 强大需要引入库字符串模拟计算自定义大数计算适用于前端特殊场景实现复杂性能较低
面试回答时最好结合具体业务场景推荐方案比如
如果是整数运算可以直接使用 BigInt。如果涉及小数运算建议使用 bignumber.js。如果环境不允许引入第三方库可使用字符串模拟计算。
这样既展现了基础知识又体现了实践经验能够给面试官留下不错的印象
88.场景面试之大文件上传上下
回答怎么解决造个开发遇到的问题然后如何解决 一、问题场景描述
假设在开发一个云盘系统时用户需要上传 10GB 以上的大文件但在实际测试中遇到以下问题
上传中断网络波动导致上传失败后需重新上传整个文件。内存溢出前端直接读取整个文件导致浏览器崩溃。进度反馈缺失用户无法感知上传进度。服务器压力大大文件直接上传占用带宽且易超时。 二、解决方案分片上传 断点续传
1. 前端核心步骤
a. 文件分片File Chunking 技术点使用 Blob.slice() 将文件切割为固定大小如 5MB的分片。 代码示例 function createChunks(file, chunkSize 5 * 1024 * 1024) {const chunks [];let start 0;while (start file.size) {chunks.push(file.slice(start, start chunkSize));start chunkSize;}return chunks;
}b. 生成文件唯一标识Hash 目的用于断点续传时识别文件。 优化使用 Web Worker SparkMD5 计算文件 Hash避免主线程阻塞。 // 在 Web Worker 中计算 Hash
self.importScripts(spark-md5.min.js);
self.onmessage async (e) {const { chunks } e.data;const spark new self.SparkMD5.ArrayBuffer();for (const chunk of chunks) {spark.append(await chunk.arrayBuffer());}self.postMessage(spark.end());
};c. 上传分片并发控制 并发控制限制同时上传的分片数如 3 个并行。 断点续传上传前向服务端查询已上传的分片列表。 async function uploadChunks(chunks, fileHash) {const uploaded await checkExistingChunks(fileHash); // 查询已上传分片const pool new ConcurrentPool(3); // 自定义并发池chunks.forEach((chunk, index) {if (!uploaded.includes(index)) {pool.addTask(() uploadChunk(chunk, index, fileHash));}});await pool.run();
}d. 进度反馈 监听每个分片进度使用 Axios 的 onUploadProgress。 汇总总进度 let uploadedSize 0;
const totalSize file.size;
chunks.forEach((chunk, index) {uploadChunk(chunk, index).then(() {uploadedSize chunk.size;updateProgress(uploadedSize / totalSize * 100);});
});2. 服务端核心步骤
a. 接收分片
接口设计POST /upload-chunk接收分片内容、文件 Hash、分片索引。存储分片将分片保存到临时目录按文件 Hash 分类存储。
b. 合并分片 接口设计POST /merge-chunks根据文件 Hash 合并所有分片。 合并逻辑Node.js 示例 function mergeChunks(fileHash, fileName) {const chunkDir path.join(UPLOAD_DIR, fileHash);const chunks fs.readdirSync(chunkDir).sort((a, b) a - b);const filePath path.join(UPLOAD_DIR, fileName);const writeStream fs.createWriteStream(filePath);chunks.forEach(chunk {const chunkPath path.join(chunkDir, chunk);writeStream.write(fs.readFileSync(chunkPath));fs.unlinkSync(chunkPath); // 删除分片});writeStream.end();
}c. 支持断点续传
记录已上传分片使用 Redis 或数据库记录文件 Hash 对应的已上传分片索引。 三、解决开发中的典型问题
问题 1分片上传后合并失败 原因分片顺序错乱或丢失。 解决方案 服务端按索引顺序合并分片。前端上传时确保分片索引连续。
问题 2Hash 计算卡顿
原因大文件 Hash 计算阻塞主线程。解决方案使用 Web Worker 异步计算。
问题 3上传进度不准确
原因未考虑分片上传失败重试。解决方案在进度计算中排除失败分片重试成功后再累加。 四、优化点
动态分片大小根据网络质量调整分片大小弱网时减小分片。秒传功能服务端校验文件 Hash 已存在时直接返回 URL。压缩分片前端对分片进行 Gzip 压缩需权衡 CPU 占用。分片哈希校验上传分片时附带分片 Hash服务端校验完整性。 五、代码片段示例前端并发控制
class ConcurrentPool {constructor(concurrency) {this.concurrency concurrency;this.queue [];this.running 0;}addTask(task) {this.queue.push(task);}async run() {while (this.queue.length 0) {if (this.running this.concurrency) {const task this.queue.shift();this.running;task().finally(() {this.running--;this.run();});} else {await new Promise(resolve setTimeout(resolve, 100));}}}
}六、总结
通过分片上传、断点续传、并发控制、进度反馈等技术组合可有效解决大文件上传的稳定性、性能和用户体验问题。核心在于前端合理拆分任务服务端高效管理分片同时结合业务需求优化传输策略。
89.场景面试之如果你是美团电影的请问怎么实现一个电影票选座功能
简要总结 核心功能 可视化座位布局Canvas/SVG 动态数据渲染。实时选座状态同步WebSocket 乐观锁冲突处理。限制选座逻辑最大数量、相邻推荐。 技术实现 前端状态管理Redux/Zustand、交互优化高亮/动画。后端座位库存管理Redis锁事务、API设计查询/锁定/合并。 难点解决 并发冲突服务端原子化操作 前端乐观更新回滚。性能瓶颈虚拟滚动/Canvas分块渲染。弱网兼容本地缓存 状态同步重试。
一句话总结通过实时通信、原子化状态管理和分层渲染优化实现高并发下的流畅选座体验核心解决数据一致性与性能问题。
89.场景面试之函数编程思想的理解
回答要点总结函数式编程思想
1. 什么是函数式编程
函数式编程FP是一种以 “纯函数”、“不可变数据” 为核心的编程范式强调 声明式编程提高代码的可读性、可复用性和可测试性。 2. 核心概念
纯函数Pure Function 相同输入必定返回相同输出无副作用。不可变数据Immutability 不直接修改数据而是返回新数据。高阶函数Higher-Order Function 函数可以接收函数作为参数或返回函数如 map、filter。柯里化Currying 将多参数函数拆成多个单参数函数提高复用性。函数组合Composition 把小函数组合成大函数提高代码整洁度。 3. 对比面向对象编程OOP
函数式编程FP面向对象编程OOP状态管理不修改状态返回新状态修改对象内部状态可测试性高可预测低状态依赖上下文适用场景数据流转换如 Redux复杂对象建模如 UI 组件 4. React 中的应用
React 组件函数组件 Hooks 遵循 FP 思想如 useState。ReduxReducer 必须是纯函数不能修改 state。高阶组件HOC 类似高阶函数提高组件复用性。 5. 典型面试回答示例
“函数式编程是一种编程范式它强调纯函数和不可变数据减少副作用提高代码可维护性。在 React 中函数式组件、Hooks、Redux 都体现了 FP 思想例如 useState 遵循不可变性Redux Reducer 也是纯函数。”
90.场景面试之前端水印功能的了解
简要总结 实现方式 CSS 背景通过重复平铺背景图或渐变生成水印但易被删除。Canvas/SVG动态生成含文字/logo的水印图转为Base64设为背景。DOM 覆盖用绝对定位的div覆盖全屏设置pointer-events: none避免遮挡操作。 动态水印 注入用户信息如ID、手机号通过前端JS生成个性化水印。 防删除 MutationObserver监听水印DOM变化被删时重新插入。Shadow DOM隐藏水印元素结构增加删除难度。 注意事项 性能优化避免频繁重绘。兼容打印场景media print 样式适配。后端校验防止前端水印被绕过关键数据需后端叠加。
核心难点平衡防护强度与性能纯前端无法绝对防篡改需结合后端验证。
91.场景面试之设计一个全站请求耗时统计工具
全站请求耗时统计工具设计
1. 需求分析
统计所有 HTTP 请求的耗时包括 API 请求、静态资源加载等。计算平均请求耗时、最大耗时、最小耗时等关键指标。兼容 fetch、XMLHttpRequestXHR、Axios 等不同请求方式。可视化展示统计数据或者上报到监控系统。 2. 方案设计
1劫持全局 fetch 和 XMLHttpRequest
在 window 作用域下拦截 HTTP 请求记录开始和结束时间计算耗时。
2存储请求数据
采用 数组 存储每次请求的耗时数据。计算 平均耗时、最大/最小耗时。采用 定时器批量上报 避免性能开销。
3数据上报
通过 定时器或阈值触发 发送统计数据到后端可结合 localStorage 做数据缓存。可视化用 Web Console 或 监控系统如 Grafana、Sentry 展示数据。 3. 代码实现
class RequestMonitor {constructor() {this.requests [];this.hookFetch();this.hookXHR();}hookFetch() {const originalFetch window.fetch;window.fetch async (...args) {const startTime performance.now();const response await originalFetch(...args);const endTime performance.now();this.logRequest(args[0], endTime - startTime);return response;};}hookXHR() {const originalOpen XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open function (...args) {this._url args[1]; // 记录请求 URLreturn originalOpen.apply(this, args);};const originalSend XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send function (...args) {const startTime performance.now();this.addEventListener(loadend, () {const endTime performance.now();requestMonitor.logRequest(this._url, endTime - startTime);});return originalSend.apply(this, args);};}logRequest(url, duration) {this.requests.push(duration);console.log([Request Monitor] ${url} 耗时: ${duration.toFixed(2)}ms);}getStats() {if (this.requests.length 0) return { avg: 0, max: 0, min: 0 };const total this.requests.reduce((sum, time) sum time, 0);return {avg: (total / this.requests.length).toFixed(2),max: Math.max(...this.requests).toFixed(2),min: Math.min(...this.requests).toFixed(2),};}
}// 启动请求监控
const requestMonitor new RequestMonitor();4. 统计 数据展示
调用 requestMonitor.getStats() 获取全站请求统计数据
console.log(全站请求耗时统计:, requestMonitor.getStats());5. 扩展优化
✅ 支持 Axios
import axios from axios;axios.interceptors.request.use(config {config.meta { startTime: performance.now() };return config;
});axios.interceptors.response.use(response {const duration performance.now() - response.config.meta.startTime;requestMonitor.logRequest(response.config.url, duration);return response;
});✅ 上报后端
setInterval(() {const stats requestMonitor.getStats();navigator.sendBeacon(/api/log, JSON.stringify(stats));
}, 60000); // 每分钟上报✅ 前端可视化 可用 Chart.js / ECharts 绘制请求耗时趋势图。 6. 总结
功能点实现方式拦截请求fetch XMLHttpRequest Axios 拦截器计算耗时performance.now() 计算请求耗时数据存储数组存储请求时间并计算平均/最大/最小耗时数据上报setInterval navigator.sendBeacon() 定时上报可视化console.log Chart.js 展示数据
92.场景面试之深度SEO优化
深度 SEO 优化方案前端视角
1. SEO 基础概念
SEOSearch Engine Optimization是搜索引擎优化的简称目标是 提高网站在搜索引擎中的排名增加自然流量。主要分为
白帽 SEO合规优化如结构化数据、关键词优化黑帽 SEO作弊手段如关键词堆砌容易被搜索引擎惩罚灰帽 SEO介于两者之间如购买外链 2. 深度 SEO 优化方案前端视角
1HTML 结构优化
✅ 语义化 HTML
使用 header article section nav 等语义化标签让搜索引擎更容易理解网页内容。
✅ Title Meta 标签
titleReact 18 Suspense 新特性解析/title
meta namedescription content本篇文章详细解析 React 18 的 Suspense 新特性帮助开发者深入理解并优化应用性能。 /
meta namekeywords contentReact, React18, Suspense, 前端, JavaScript /title简短、包含主要关键词。meta description控制搜索引擎摘要提高点击率CTR。meta keywords部分搜索引擎已不使用但仍可提供参考。
✅ H1-H6 结构
h1React 18 Suspense 新特性解析/h1
h21. 什么是 Suspense/h2
h22. 如何使用 Suspense/h2H1 只能有一个确保核心主题明确。H2-H6 作为层级结构帮助搜索引擎理解文章内容。
✅ 图片优化
img srcsuspense-example.png altReact 18 Suspense 示例代码 /使用 alt 属性描述图片内容提升无障碍体验 SEO。使用 loadinglazy 实现懒加载优化性能。
✅ 结构化数据Schema.org
增强搜索结果支持 富文本摘要。
script typeapplication/ldjson
{context: https://schema.org,type: Article,headline: React 18 Suspense 新特性解析,author: { type: Person, name: 张三 },datePublished: 2025-03-04,publisher: { type: Organization, name: 前端社区 }
}
/script2前端技术优化
✅ SSR服务器端渲染
React Next.js 或 Nuxt.jsVue让搜索引擎爬虫直接获取完整 HTML 内容提高抓取效率。
✅ 静态站点生成SSG
适用于内容不经常变动的网站例如博客、文档站点Gatsby.js、Next.js。
✅ 懒加载与代码拆分
避免首屏加载过大提高首屏加载速度搜索引擎更喜欢快的网站。
const LazyComponent React.lazy(() import(./LazyComponent));3性能优化
✅ 页面加载速度
使用 Lighthouse 分析 Core Web Vitals核心网页指标。减少阻塞渲染的 JS/CSS
link relpreload hrefstyle.css asstyle启用 Gzip / Brotli 压缩 及 HTTP/2。使用 CDN如 Cloudflare优化静态资源加载。
✅ 图片优化
WebP 格式 替代 PNG/JPG提升加载速度。使用 srcset 提供不同分辨率图片。
img srcimage.jpg srcsetimage-2x.jpg 2x, image-3x.jpg 3x /✅ 减少不必要的重定向
避免 多个 301/302 跳转影响 SEO 排名。 4移动端优化
✅ 响应式设计
使用 meta viewport适配移动端。
meta nameviewport contentwidthdevice-width, initial-scale1✅ PWA渐进式 Web 应用
提供离线缓存、首页安装功能提高用户体验。 5外链与内部链接优化
✅ 合理的 URL 结构
URL 短而清晰如
❌ /article?id12345
✅ /react-18-suspense✅ 内链优化
文章内部使用锚点链接提升爬取效率。
a href/react-18-suspense深入了解 React 18 Suspense/a✅ 外链策略
提供权威性高的外链如 MDN、Google 开发者文档。处理 死链 404使用 robots.txt 或 301 重定向。 6SEO 监控与优化
✅ Sitemap.xml
urllochttps://www.example.com/react-18-suspense/loclastmod2025-03-04/lastmodpriority0.8/priority
/url让搜索引擎更快索引你的站点。
✅ robots.txt
User-agent: *
Disallow: /admin/
Allow: /阻止搜索引擎爬取无关页面如后台管理系统。
✅ Google Search Console 百度搜索资源平台
提交 Sitemap.xml 让爬虫更快发现新内容。监测 抓取错误 索引情况。
✅ Lighthouse 测试
npx lighthouse https://www.example.com --view通过 Chrome DevTools 进行性能 SEO 评分分析。 7. 总结
优化点实现方式HTML 结构语义化标签、Title、Meta、H1-H6、Alt 图片技术选型SSRNext.js、SSGGatsby、静态优化性能优化懒加载、CDN、WebP、代码拆分移动端适配响应式设计、PWA外链 内链清晰 URL、站内站外链接优化SEO 监控Sitemap、robots.txt、Google Search Console
这样回答既 系统全面又 有前端落地方案面试官肯定会满意
93.场景面试之图片性能优化的方案
前端图片性能优化方案
1. 选择合适的图片格式 WebP/AVIF现代格式压缩率高支持透明和动画。使用 picture 标签提供回退 picturesource srcsetimage.avif typeimage/avifsource srcsetimage.webp typeimage/webpimg srcimage.jpg alt示例
/pictureSVG矢量图形适合图标和简单图形缩放无损。
2. 图片压缩与优化
工具压缩使用工具如 Squoosh、TinyPNG降低文件大小。质量取舍调整压缩率如 JPEG 质量设为 60-80%。
3. 响应式图片加载 srcset 与 sizes按设备分辨率/视口宽度加载合适尺寸 img srcsmall.jpgsrcsetmedium.jpg 1000w, large.jpg 2000wsizes(max-width: 600px) 100vw, 50vw4. 懒加载技术 原生属性loadinglazy兼容现代浏览器 img srcplaceholder.jpg data-srcimage.jpg loadinglazyIntersection Observer API动态加载可视区域图片 const observer new IntersectionObserver((entries) {entries.forEach(entry {if (entry.isIntersecting) {const img entry.target;img.src img.dataset.src;observer.unobserve(img);}});
});
document.querySelectorAll(img[data-src]).forEach(img observer.observe(img));5. CDN 与缓存策略
CDN 加速通过全球节点分发减少延迟。缓存控制设置 Cache-Control: max-age31536000 并添加哈希文件名如 image-abc123.jpg实现长期缓存。
6. 减少 HTTP 请求 HTTP/2 多路复用替代雪碧图并行加载小文件。 内联小图Base64 编码适用于 1KB 图片 .icon {background: url(data:image/png;base64,...);
}7. 渐进式加载与占位符
渐进式 JPEG逐步渲染提升感知速度。LQIP (低质量占位符) 先加载模糊缩略图再替换为高清图。
8. 替代方案与高级优化 CSS/SVG 替代效果阴影、渐变、图标字体减少图片依赖。 视频替代 GIF使用 MP4 格式体积减少 80% video autoplay loop muted playsinlinesource srcanimation.mp4 typevideo/mp4
/video9. 预加载关键资源 link relpreload 提前加载首屏重要图片 link relpreload hrefhero-image.jpg asimage10. 监控与自动化
性能工具Lighthouse、WebPageTest 分析优化点。自动化处理构建工具Webpack集成 image-webpack-loader 自动压缩。
总结
综合应用格式选择、懒加载、CDN 和响应式设计平衡质量与性能。优先优化首屏资源持续监控调整策略。
94.场景面试之1000w行的表格你如何渲染性能问题那么多的dom节点怎么精简
前端渲染1000万行表格的优化方案 1. 核心问题分析
DOM 数量爆炸1000万行直接渲染会导致内存占用过高约 2GB页面崩溃。渲染性能差DOM 操作阻塞主线程滚动卡顿。交互延迟事件监听器过多响应缓慢。 2. 核心解决方案虚拟滚动Virtual Scrolling
原理仅渲染可视区域内的行动态替换内容保持 DOM 节点数恒定如 50-100个。 实现步骤 计算可视区域 获取容器高度如 600px和行高如 30px→ 每屏显示 20 行。 监听滚动事件 根据滚动位置计算起始索引startIndex Math.floor(scrollTop / rowHeight)。 动态渲染数据 截取 data.slice(startIndex, startIndex 20) 进行渲染。 占位元素撑开滚动条 设置总高度为 totalHeight rowHeight * 1e7模拟完整滚动范围。
代码示例
const container document.getElementById(table);
const rowHeight 30;
let startIndex 0;function renderVisibleRows() {const scrollTop container.scrollTop;startIndex Math.floor(scrollTop / rowHeight);const endIndex startIndex Math.ceil(container.clientHeight / rowHeight);// 清空现有行container.innerHTML ;// 添加可视行for (let i startIndex; i endIndex; i) {const row document.createElement(div);row.style.height ${rowHeight}px;row.textContent Row ${i 1};container.appendChild(row);}// 设置占位高度container.style.height ${rowHeight * 1e7}px;
}container.addEventListener(scroll, renderVisibleRows);
renderVisibleRows(); // 初始渲染3. 性能优化进阶
a. 减少 DOM 复杂度
简化结构用 div 替代 table避免浏览器重排开销。复用 DOM 节点池化已创建的 DOM 元素减少创建/销毁开销。
b. 异步渲染分块 使用 requestAnimationFrame 或 setTimeout 分块更新避免阻塞主线程 function chunkedRender() {let i 0;function renderChunk() {for (let j 0; j 10; j) {if (i data.length) return;// 渲染第 i 行i;}requestAnimationFrame(renderChunk);}renderChunk();
}c. 高效数据存储
二进制数据使用 ArrayBuffer 或 TypedArray 存储数值型数据减少内存占用。按需加载通过 WebSocket 或分页 API 动态加载数据避免一次性加载 1000 万条。
d. 禁用高耗能操作 避免在行元素上绑定独立事件监听器改用事件委托 container.addEventListener(click, (e) {const row e.target.closest(.row);if (row) handleRowClick(row.dataset.id);
});4. 替代方案Canvas 渲染
适用场景纯展示型表格交互需求少。 优势
数万行数据流畅渲染直接绘制无 DOM 开销。支持复杂视觉效果渐变、动画。
实现思路
绘制表头、表格线。根据滚动位置计算渲染的数据范围。使用 canvas.drawText() 绘制文本内容。
限制
文本选择、点击交互需手动实现通过坐标计算命中区域。 5. 使用现成库加速开发 React 生态 react-window支持虚拟滚动列表/表格。react-virtualized高级功能动态行高、缓存。 Vue 生态 vue-virtual-scroller轻量级虚拟滚动。 原生 JS 库 lit-virtualizerPolymer 团队。 6. 极端优化手段
Web Worker 预处理将排序/过滤操作移至 Worker 线程。GPU 加速对固定部分使用 transform: translateZ(0) 触发硬件加速。增量渲染优先渲染首屏逐步加载剩余数据。 总结
方案适用场景优点缺点虚拟滚动高交互需求编辑、复杂样式平衡性能与功能实现复杂度较高Canvas 渲染纯展示、超大数据量100万行极致性能无 DOM 限制交互实现复杂分页/懒加载非实时性需求简单易实现用户体验不连贯
核心原则
按需渲染绝不在同一时间操作超过 1000 个 DOM 节点。减少重排/重绘使用绝对定位、CSS Transform 等优化渲染。内存管理及时销毁不可见数据避免内存泄漏。
95.场景面试之怎么实现前端页面截图
场景面试如何实现前端页面截图
在面试中回答如何实现前端页面截图需要结合 不同的应用场景 和 可行方案并说明 技术选型的理由。 1. 需求分析
前端页面截图通常涉及以下几种场景
用户截取当前可见区域用户截取整个网页滚动截图截取指定 DOM 元素下载截图并分享截图后进行编辑如裁剪、标注 2. 方案选择
方法 1使用 html2canvas适用于可见区域 DOM 截图
✅ 适用场景
截取 可见区域 或 指定 DOM 元素适用于 现代浏览器纯前端实现不依赖服务器 实现步骤
安装 html2canvas
npm install html2canvas代码实现
import html2canvas from html2canvas;const captureScreenshot async () {const element document.getElementById(captureArea); // 选择截图区域const canvas await html2canvas(element, {useCORS: true, // 解决跨域图片问题backgroundColor: null, // 透明背景});const imgURL canvas.toDataURL(image/png); // 转换为 base64 图片const link document.createElement(a);link.href imgURL;link.download screenshot.png; // 下载截图link.click();
};优缺点
优势劣势纯前端实现无需后端支持不支持跨域图片需要 useCORS: true可截取指定 DOM 元素无法截取 iframe、视频等适用于用户可见区域滚动截图支持不完善 方法 2使用 dom-to-image改进 html2canvas支持更多特性
✅ 适用场景
需要更精准的 DOM 截图支持 SVG、字体嵌入适用于 动态内容 实现代码
import domtoimage from dom-to-image;const captureDomImage () {const node document.getElementById(captureArea);domtoimage.toPng(node).then(dataUrl {const link document.createElement(a);link.href dataUrl;link.download screenshot.png;link.click();}).catch(error console.error(截图失败:, error));
};优缺点
优势劣势比 html2canvas 兼容性更好仍然无法截图 iframe、视频支持 SVG、Web 字体性能可能比 html2canvas 略慢 方法 3使用 puppeteer适用于整页截图服务器端渲染
✅ 适用场景
后台批量生成网页截图支持滚动截图可截图 iframe 和跨域内容 实现步骤
安装 Puppeteer
npm install puppeteerNode.js 代码
const puppeteer require(puppeteer);(async () {const browser await puppeteer.launch();const page await browser.newPage();await page.goto(https://example.com, { waitUntil: networkidle2 });// 截取整个页面await page.screenshot({ path: screenshot.png, fullPage: true });await browser.close();
})();优缺点
优势劣势可截取整页支持滚动需要服务器支持Node.js支持 iframe、视频、跨域不能直接在前端运行 方法 4使用 canvas 结合 drawImage()适用于视频或 iframe 截图
✅ 适用场景
需要截取 iframe 或 视频适用于 动态内容截图 实现代码
const captureVideoFrame (videoElement) {const canvas document.createElement(canvas);canvas.width videoElement.videoWidth;canvas.height videoElement.videoHeight;const ctx canvas.getContext(2d);ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);const imgURL canvas.toDataURL(image/png);return imgURL;
};const video document.querySelector(video);
const screenshot captureVideoFrame(video);
console.log(截图 Base64:, screenshot);优缺点
优势劣势可截取 video 或 iframe只能截取当前帧适用于动态内容需要用户交互如 play() 后再截图 3. 选型对比
方案适用场景支持滚动截图支持 iframe依赖html2canvas可见区域、DOM 截图❌❌纯前端dom-to-image更精准的 DOM 截图❌❌纯前端puppeteer整页截图、后台爬虫✅✅Node.js 服务器canvas drawImage()视频截图❌✅纯前端 4. 总结
最佳方案
普通网页截图可见区域 → html2canvas / dom-to-image完整网页截图包括滚动 → puppeteer视频 / iframe 截图 → canvas.drawImage()
面试回答时可以结合具体业务场景提出最合适的解决方案同时说明 优缺点 和 技术选型依据这样更显得专业
96.场景面试之移动端适配问题如何解决
场景面试移动端适配问题如何解决
在前端面试中针对移动端适配问题最佳的回答方式是 先分析适配的常见问题再 提出不同的解决方案最后 结合具体场景推荐最佳方案。 1. 移动端适配的常见问题
设备屏幕尺寸多样化不同设备宽高比、像素密度不同不同 DPR设备像素比 如 Retina 屏1px 在高分屏上可能占多个物理像素不同系统、浏览器的默认样式iOS/Android/Chrome/Safari/微信浏览器差异字体、图片模糊问题高分屏需要更高清的图片资源触摸事件与鼠标事件的差异点击延迟、滑动优化 2. 适配方案
针对以上问题常见的适配方案有以下几种
方案 1使用 viewport 进行屏幕缩放
在 head 中添加 meta viewport 控制视口
meta nameviewport contentwidthdevice-width, initial-scale1, maximum-scale1, user-scalableno✅ 优点
控制视口宽度避免缩放影响布局user-scalableno 防止用户缩放页面
❌ 缺点
不能解决不同设备 px 值不一样的问题 方案 2CSS 响应式布局媒体查询
使用 media 适配不同屏幕
media screen and (max-width: 768px) {body {font-size: 14px;}
}media screen and (max-width: 375px) {body {font-size: 12px;}
}✅ 优点
适用于各种尺寸设备代码易读适用于 rem/em 配合 viewport
❌ 缺点
需要手动编写多套样式维护成本较高 方案 3使用 rem vw 进行动态适配
使用 rem配合 html 动态 font-size
设置 html 根字体大小
function setRem() {const baseSize 16;const scale document.documentElement.clientWidth / 375; // 以 iPhone 6375px为基准document.documentElement.style.fontSize ${baseSize * scale}px;
}
setRem();
window.onresize setRem; // 监听窗口变化使用 rem 进行布局
.container {width: 10rem; /* 适配不同设备 */
}使用 vwCSS 直接适配
.container {width: 50vw; /* 视口宽度的 50% */
}✅ 优点
rem 适用于不同屏幕 px 变化vw 适用于 全屏自适应布局
❌ 缺点
rem 需要动态计算 font-sizevw 在小屏幕下可能导致内容过大 方案 4使用 flex 和 grid 进行自适应布局
使用 flex 可以适配不同屏幕
.container {display: flex;flex-wrap: wrap;justify-content: space-between;
}✅ 优点
适用于不同屏幕不需要手动指定 width自适应效果好
❌ 缺点
仅适用于 容器内部元素布局 方案 5使用 图片 和 文字 的 DPR 适配
高清图片
media screen and (-webkit-min-device-pixel-ratio: 2),screen and (min-resolution: 192dpi) {.logo {background-image: url(logo2x.png);}
}CSS image-set
.logo {background-image: image-set(logo.png 1x,logo2x.png 2x,logo3x.png 3x);
}✅ 优点
适配 Retina 屏幕图片更清晰
❌ 缺点
需要提供不同 DPR 版本的图片资源 3. 选型对比
方案适用场景适配能力代码复杂度维护成本meta viewport适配初始缩放⭐⭐⭐⭐⭐media 媒体查询适配不同设备⭐⭐⭐⭐⭐⭐⭐rem vw全局适配⭐⭐⭐⭐⭐⭐⭐⭐⭐flex/grid自适应布局⭐⭐⭐⭐⭐⭐⭐DPR 适配高分屏优化⭐⭐⭐⭐⭐⭐⭐ 4. 总结
最佳适配方案
小型项目简单适配 → viewport media中型项目动态布局 → rem vw大型项目高分屏 灵活适配 → flex vw DPR 适配
97.场景题之web应用中如何对静态资源加载失败的场景做降级处理
场景题Web 应用中如何对静态资源加载失败的场景做降级处理
在 Web 应用中静态资源如 CSS、JS、图片、字体等可能由于 CDN 故障、网络问题、文件丢失 等原因加载失败。为了保证用户体验需要实现 降级处理确保页面在关键资源缺失时仍能正常运行。 1. 常见静态资源加载失败的原因
CDN 资源不可用服务器宕机、DNS 解析失败网络问题用户网络波动、弱网环境浏览器拦截CORS 限制、广告拦截插件文件丢失或路径错误错误的资源 URL版本更新问题缓存未更新导致 404 2. 具体降级方案
针对不同类型的静态资源采用不同的降级策略 (1) JavaScript 资源降级
问题核心 JS 资源如 Vue、React 框架加载失败可能导致页面无法交互。 解决方案
多 CDN 备选方案动态切换
script srchttps://cdn1.example.com/react.min.js onerrorloadFallbackJS()/script
scriptfunction loadFallbackJS() {var script document.createElement(script);script.src https://cdn2.example.com/react.min.js;document.head.appendChild(script);}
/script本地备份CDN 本地
script srchttps://cdn.example.com/vue.min.js onerrorthis.onerrornull;this.src/local/vue.min.js/script✅ 优点减少单点依赖保障 JS 可用 ❌ 缺点可能造成一定的延迟 (2) CSS 资源降级
问题CSS 失败可能导致页面错乱 解决方案
备用 CSS多 CDN 或本地降级
link relstylesheet hrefhttps://cdn.example.com/style.css onerrorthis.onerrornull;this.href/fallback/style.css;使用 noscript 兜底 如果 JS 和 CSS 都失效可以提供最基本的 noscript 样式
noscriptlink relstylesheet href/fallback/basic.css
/noscript✅ 优点确保最基本的样式可用 ❌ 缺点无法应对所有 CSS 丢失的情况 (3) 图片资源降级
问题图片加载失败影响用户体验 解决方案
使用默认占位图
img srchttps://cdn.example.com/avatar.jpg onerrorthis.onerrornull;this.src/fallback/default-avatar.jpg;使用 object-fit 确保布局稳定
img {width: 100px;height: 100px;object-fit: cover;background-color: #f0f0f0; /* 避免显示空白 */
}✅ 优点避免图片影响布局 ❌ 缺点占位图可能无法满足所有业务需求 (4) 字体资源降级
问题Web 字体加载失败会导致 FOUTFlash of Unstyled Text或页面显示异常 解决方案
使用 font-display: swap
font-face {font-family: CustomFont;src: url(/fonts/custom.woff2) format(woff2);font-display: swap;
}✅ 优点优先使用系统字体避免页面空白 ❌ 缺点字体可能会有短暂的切换闪烁
提供多个字体备选
body {font-family: CustomFont, Arial, sans-serif;
}✅ 优点保证页面最起码的可读性 (5) 整体降级策略
当多个资源加载失败时可以通过 JS 监控 策略性降级 提供更优体验
全局监听资源加载失败
window.addEventListener(error, function (event) {if (event.target.tagName SCRIPT) {console.error(JS 加载失败尝试使用备用方案);loadFallbackJS();} else if (event.target.tagName LINK) {console.error(CSS 加载失败加载降级样式);document.head.insertAdjacentHTML(beforeend,link relstylesheet href/fallback/style.css);} else if (event.target.tagName IMG) {event.target.src /fallback/default-image.jpg;}
}, true);✅ 优点全局监控并自动降级 ❌ 缺点可能增加额外的降级逻辑 3. 监控与上报
为了防止资源加载失败影响用户体验可以上报错误并分析
window.addEventListener(error, function (event) {fetch(/log/error, {method: POST,body: JSON.stringify({type: event.target.tagName,url: event.target.src || event.target.href,time: new Date().toISOString()})});
}, true);✅ 优点帮助分析资源加载失败原因 ❌ 缺点需要额外的日志存储服务 4. 总结 资源降级策略对比
资源类型降级方案适用场景额外成本JS 资源备用 CDN / 本地备份核心框架 业务 JS低CSS 资源备用 CDN / noscript 方案关键样式低图片资源默认占位图头像、Banner低字体资源font-display: swap / 备用字体自定义字体低监控 上报window.addEventListener(error)统计加载失败中 面试回答建议
先分析问题静态资源加载失败的原因再提供不同资源类型的降级方案最后补充监控 上报方案结合实际场景选择最优方案
这样回答既展现了技术广度覆盖 JS、CSS、图片、字体等资源又体现了深度主动监控 降级方案 上报分析
98.场景题之如何修改第三方npm包
场景题如何修改第三方 NPM 包
在实际开发中有时候我们需要修改 第三方 NPM 包可能是因为
Bug 修复第三方库存在未修复的问题功能扩展需要新增或修改原有功能兼容性问题与当前项目或新版本的依赖冲突个性化定制需要更改样式、逻辑、API 等
下面介绍 不同场景下的修改方式并分析 优缺点。 方式 1直接修改 node_modules 目录下的文件不推荐
✅ 适用场景
临时调试或快速验证修改是否生效
❌ 缺点
npm install 或 pnpm install 后会被覆盖团队协作难以维护
示例
cd node_modules/some-package
vim index.js # 直接修改文件不推荐修改后不能持久化 方式 2使用 patch-package 生成补丁推荐
✅ 适用场景
修改第三方包 但不想手动维护 fork 版本可持续管理修改方便团队协作
步骤
安装 patch-package
npm install patch-package postinstall-postinstall --save-devpostinstall-postinstall 确保补丁在 npm install 后自动应用 修改 node_modules 内的代码
vim node_modules/some-package/index.js # 进行修改生成补丁
npx patch-package some-package生成 patches/some-package1.0.0.patch 文件记录改动 在 package.json 添加 postinstall
scripts: {postinstall: patch-package
}提交 patches 目录到 Git
git add patches
git commit -m fix: modify some-package for compatibility优点
✅ 不会丢失npm install 后会自动应用补丁✅ 团队协作友好代码改动可被 Git 追踪✅ 不影响原包的更新可随时调整 推荐使用 方式 3Fork 该 NPM 包维护自己的版本
✅ 适用场景
长期维护 或 修改较多 的情况下官方仓库不接受 PR 或修复周期太长
步骤
Fork 该 NPM 包的 GitHub 仓库在本地克隆
git clone https://github.com/your-username/some-package.git
cd some-package修改代码发布到 NPM可选
npm version patch # 更新版本号
npm publish --access public # 发布自己的 NPM 包使用修改后的包
npm install your-username/some-package优点
✅ 完全掌控代码可随时更新✅ 适用于大规模修改
❌ 缺点
需要自己维护更新官方如果有新版本需要手动同步 适合长期定制需求 方式 4在项目代码中重新封装
✅ 适用场景
仅修改部分 API但不想改动原包
思路
通过继承或高阶函数封装代理某些方法增强功能拦截包的导入替换原实现
示例 1封装增强功能
import OriginalLib from some-package;export default function CustomLib(...args) {const instance new OriginalLib(...args);// 增强方法instance.newMethod function () {console.log(This is a custom method!);};return instance;
}示例 2Webpack / Vite Alias 直接替换原包
alias: {some-package: /src/custom-some-package.js
}适合小修改减少维护成本 总结
方式适用场景优点缺点直接修改 node_modules快速调试立即生效不能持久化安装后会丢失patch-package ✅推荐修改少量代码易维护自动应用仍依赖原包适用小改动Fork 仓库 维护长期维护/大改动完全掌控代码需要自己维护更新封装重写修改 API / 兼容性低维护成本不影响原包适用于部分 API 的调整 最佳实践
小改动用 patch-package大改动 Fork 维护不想改源码就封装 API
99.场景题之实现网页加载进度条
场景题实现网页加载进度条
在 Web 开发中加载进度条 可以提升用户体验常见的场景包括
单页应用SPA 页面切换时的加载进度页面资源加载CSS/JS/图片等异步请求加载Ajax 请求、接口调用长时间任务文件上传、数据处理 方案 1使用 NProgress 实现进度条推荐
NProgress 是一个轻量级的进度条库能在 页面加载或 AJAX 请求时 显示进度条。
安装 NProgress
npm install nprogress基本使用
import NProgress from nprogress;
import nprogress/nprogress.css; // 引入样式// 页面开始加载时
NProgress.start();// 页面加载完成
NProgress.done();与 fetch 结合
NProgress.start();
fetch(https://api.example.com/data).then(response response.json()).finally(() NProgress.done());优点
简单易用适合异步请求、路由跳转可自定义样式自动处理多次请求 适合大多数场景推荐 方案 2基于 XMLHttpRequest 监听网络请求进度
对于 文件上传 或 大数据请求可以使用 XMLHttpRequest 监听 progress 事件。
const xhr new XMLHttpRequest();
xhr.open(GET, https://api.example.com/large-file, true);xhr.onprogress function (event) {if (event.lengthComputable) {let percent (event.loaded / event.total) * 100;console.log(加载进度${percent.toFixed(2)}%);}
};xhr.onload function () {console.log(加载完成);
};xhr.send();适用场景
大文件下载流式加载 适用于特定场景如文件上传 方案 3基于 window.onload 监听静态资源加载
用于 网页所有资源CSS/JS/图片加载完毕 时显示进度条。
div idprogress-bar stylewidth: 0%; height: 5px; background: blue; position: fixed; top: 0; left: 0;/div
scriptlet progressBar document.getElementById(progress-bar);function updateProgress(percent) {progressBar.style.width percent %;}document.addEventListener(DOMContentLoaded, () updateProgress(50));window.onload () updateProgress(100);
/script适用场景
整页加载首屏优化 适合全局加载进度条 方案 4监听路由变化适用于 Vue / React
对于 单页应用SPA 可以监听路由变化并在切换时显示进度条。
Vue 结合 NProgress
import NProgress from nprogress;
import { createRouter, createWebHistory } from vue-router;const router createRouter({history: createWebHistory(),routes: [ /* 路由配置 */ ]
});router.beforeEach(() NProgress.start());
router.afterEach(() NProgress.done());React 结合 NProgress
import { useEffect } from react;
import NProgress from nprogress;
import { useLocation } from react-router-dom;const ProgressBar () {const location useLocation();useEffect(() {NProgress.start();return () NProgress.done();}, [location.pathname]);return null;
};export default ProgressBar;适用场景
Vue / React 单页应用路由切换时显示进度 单页应用推荐方案 总结
方案适用场景优点缺点NProgress ✅推荐Ajax、SPA 路由简单易用UI 友好需引入库XMLHttpRequest 进度监听文件上传、大数据进度精准仅适用于请求window.onload 资源加载静态资源、首屏优化适用于整页不适用于 AJAXVue/React 路由进度条单页应用结合 NProgress效果好需框架支持
最佳实践
AJAX / 路由加载 ➝ NProgress文件上传 ➝ XMLHttpRequest 监听 progress整页加载 ➝ window.onloadVue / React ➝ 结合 beforeEach/useEffect
100.场景题之小程序双线程模型
小程序双线程模型解析 1. 核心架构
小程序采用**渲染层View Layer和逻辑层App Service Layer**分离的双线程模型通过 Native客户端 桥接通信实现安全性与性能的平衡。 2. 线程职责
线程运行环境核心职责限制渲染层WebViewiOS WKWebView / Android X5- 页面渲染WXML/WXSS- 用户交互事件监听无法直接执行 JavaScript 业务逻辑逻辑层JavaScriptCoreiOS / V8Android- 业务逻辑处理JS- 数据管理setData- 调用原生 API无法直接操作 DOM 3. 通信机制 事件驱动 用户交互如点击渲染层捕获事件 → 通过 WeixinJSBridge 通知逻辑层。数据更新逻辑层调用 setData → 数据序列化为字符串 → Native 转发 → 渲染层解析并更新视图。 // 逻辑层业务逻辑
Page({handleClick() {this.setData({ text: Updated }); // 数据变更通知渲染层}
});通信优化 数据合并多次 setData 调用合并为一次通信。局部更新仅传递变化的数据字段减少传输量。 4. 设计优势 安全性 逻辑层无法直接操作 DOM防止恶意脚本攻击。敏感 API如支付由 Native 层控制JS 需通过权限申请。 性能 渲染与逻辑分离避免单线程阻塞如长耗时逻辑不影响页面渲染。WebView 与 JS 引擎独立内存管理更高效。 稳定性 单页面崩溃不影响整体应用各页面渲染层独立。 5. 性能瓶颈与优化 通信开销 问题频繁 setData 或大数据量传输导致延迟。 解决 使用 this.data.xxx 直接修改数据仅在必要时调用 setData。分页加载数据避免一次性传递超长列表。 渲染层性能 问题复杂动画或过多节点导致卡顿。 解决 使用 CSS 动画替代 JS 动画。简化 WXML 结构减少嵌套层级。 6. 与 Web 单线程模型的对比
对比项Web 单线程模型小程序双线程模型线程模型渲染、逻辑、DOM 操作均在同一线程渲染与逻辑分离Native 桥接通信安全性可通过 JS 直接操作 DOM风险较高逻辑层无法操作 DOM安全性更强性能瓶颈长任务阻塞渲染如复杂计算通信延迟逻辑与渲染层数据传递开发限制无强制限制灵活性高API 调用受限需遵循小程序规范 7. 典型场景示例
用户输入实时搜索
渲染层监听输入事件 → 通知逻辑层。逻辑层防抖处理 → 发起网络请求。请求返回后通过 setData 更新列表 → 渲染层重新渲染。 优化点
防抖减少请求次数。仅更新差异数据避免全列表刷新。 总结
双线程模型通过逻辑与渲染隔离保障了小程序的安全与流畅性但开发者需注意
控制 setData 的频率与数据量。避免在渲染层执行复杂逻辑。合理使用 Native 能力如 Worker处理耗时任务。 这一设计是小程序高性能、高安全性的基石但也对开发者的优化意识提出了更高要求。
101.场景题之如何使用一个链接实现PC打开是web应用手机打开是h5应用
解决方案通过设备检测实现自适应内容分发
1. 核心思路
使用 服务端 User-Agent 检测 区分设备类型同一 URL 返回 PC 或 H5 的不同前端资源实现“一链双端”。 2. 实现方案
方案一服务端动态渲染SSR 步骤 检测 User-Agent服务端如 Node.js、Nginx解析请求头中的 User-Agent。 返回对应内容 PC返回 PC 版 HTML/CSS/JS。移动端返回 H5 版 HTML/CSS/JS。 代码示例Node.js const express require(express);
const mobileDetect require(mobile-detect);
const app express();app.get(/, (req, res) {const md new mobileDetect(req.headers[user-agent]);if (md.mobile()) {res.sendFile(h5-index.html, { root: ./h5 });} else {res.sendFile(pc-index.html, { root: ./pc });}
});优点 URL 不变无重定向延迟。SEO 友好可针对不同设备优化内容。
方案二Nginx 路径分发 配置示例 map $http_user_agent $device {default pc;~*(android|iphone|ipod|ipad) mobile;
}server {location / {root /usr/share/nginx/html/$device;try_files $uri $uri/ /index.html;}
}说明 根据 UA 将请求映射到 pc 或 mobile 目录加载不同前端资源。
方案三前端动态加载CSR 步骤 前端通过 JS 检测设备类型。动态加载对应版本的组件或路由。 // 检测移动端
const isMobile /Android|iPhone|iPad/i.test(navigator.userAgent);// 动态加载组件
if (isMobile) {import(./H5App).then(module render(module.default));
} else {import(./PCApp).then(module render(module.default));
}缺点 首屏加载所有代码影响性能。无法彻底隔离 PC/H5 的依赖包。 3. 关键优化点 精准 UA 检测 使用成熟库如 mobile-detect、react-device-detect提高识别准确率。 缓存策略 设置 Vary: User-Agent 响应头避免 CDN 缓存混淆不同设备内容。 降级方案 当检测失败时默认返回 PC 版并提供跳转链接如“切换到移动版”。 SEO 处理 确保 PC/H5 页面核心内容一致避免被判定为“内容重复”。 4. 方案对比
方案适用场景优点缺点服务端动态渲染需严格区分功能/设计的场景性能高、SEO 友好需维护两套前端代码Nginx 分发静态资源托管场景配置简单、无业务逻辑侵入灵活性较低前端动态加载功能差异较小的轻量级应用单代码库维护首屏性能差、包体积大 5. 高级场景响应式 动态增强 混合方案 基础 UI 使用响应式布局适配所有设备。针对复杂功能如大屏图表通过 UA 检测动态加载 PC 专属模块。 // 响应式布局 按需加载
if (!isMobile isDataVisualizationPage) {import(heavy-charts-module).then(initCharts);
}总结 推荐方案服务端动态渲染SSR或 Nginx 分发优先保证性能与体验一致性。 核心原则 设备检测精准化避免误判导致功能错乱。代码维护低成本通过组件复用减少双端开发量。用户体验无缝衔接确保 URL 一致功能切换自然。
102.场景题之移动端上拉加载下拉刷新实现方案
场景题移动端上拉加载 下拉刷新
在移动端开发中上拉加载加载更多数据和 下拉刷新重新获取最新数据是常见的交互方式常用于 列表、新闻流、商品展示等页面。 一、核心思路 下拉刷新Pull to Refresh 用户下拉页面触发 数据刷新适用于最新数据加载如 新闻、社交动态依赖 touchstart touchmove touchend 事件也可以用 原生 WebView 下拉刷新 或 JS 框架支持 上拉加载Infinite Scroll 用户滑动到底部自动加载更多数据适用于分页数据如 商品列表、文章列表依赖 scroll 事件 或 IntersectionObserver 二、手写原生实现
1. 下拉刷新手写实现
let startY 0;
let isRefreshing false;document.addEventListener(touchstart, (e) {startY e.touches[0].pageY;
});document.addEventListener(touchmove, (e) {if (isRefreshing) return;let moveY e.touches[0].pageY - startY;if (moveY 50) { // 下拉阈值console.log(触发刷新...);isRefreshing true;refreshData();}
});function refreshData() {setTimeout(() {console.log(数据刷新完成);isRefreshing false;}, 1500);
}适用场景
适合轻量级项目可结合 CSS 增强效果手动实现可定制性高 优化方向
添加动画效果例如旋转 loading 图标防止多次触发结合CSS3 transform 过渡 2. 上拉加载监听滚动事件
window.addEventListener(scroll, () {let scrollTop document.documentElement.scrollTop || document.body.scrollTop;let clientHeight document.documentElement.clientHeight;let scrollHeight document.documentElement.scrollHeight;if (scrollTop clientHeight scrollHeight - 10) {console.log(触发加载更多...);loadMoreData();}
});function loadMoreData() {setTimeout(() {console.log(加载完成);}, 1000);
}适用场景
适合PC 移动端兼容性较好但 scroll 事件可能会触发频繁 优化方向
防抖优化减少滚动触发频率监听 scrollHeight 变化防止无限触发 3. 上拉加载IntersectionObserver 方案
现代浏览器推荐使用 IntersectionObserver 监听目标元素是否进入视口。
let observer new IntersectionObserver((entries) {if (entries[0].isIntersecting) {console.log(触发加载更多...);loadMoreData();}
});observer.observe(document.querySelector(#load-more));适用场景
性能更优比 scroll 监听更高效适用于 商品列表、无限滚动 三、使用前端框架Vue/React
1. Vue 实现
Vue 推荐使用 vueuse/useScroll 或 better-scroll
templatediv reflist scrollonScrolldiv v-foritem in listData :keyitem.id{{ item.title }}/divdiv v-ifloading加载中.../div/div
/templatescript setup
import { ref } from vue;const listData ref([...Array(20).keys()]); // 模拟数据
const loading ref(false);const onScroll (e) {const { scrollTop, scrollHeight, clientHeight } e.target;if (scrollTop clientHeight scrollHeight - 10 !loading.value) {loadMoreData();}
};const loadMoreData () {loading.value true;setTimeout(() {listData.value.push(...Array(10).keys());loading.value false;}, 1000);
};
/script适用场景
适用于 Vue 2 Vue 3可结合 better-scroll 提供更流畅滚动 2. React 实现
React 也可以使用 useEffect IntersectionObserver
import { useEffect, useState, useRef } from react;const InfiniteScroll () {const [items, setItems] useState(Array.from({ length: 20 }));const [loading, setLoading] useState(false);const loadMoreRef useRef(null);useEffect(() {const observer new IntersectionObserver(([entry]) {if (entry.isIntersecting !loading) {setLoading(true);setTimeout(() {setItems((prev) [...prev, ...Array.from({ length: 10 })]);setLoading(false);}, 1000);}});if (loadMoreRef.current) observer.observe(loadMoreRef.current);return () observer.disconnect();}, [loading]);return (div{items.map((_, index) (div key{index}Item {index}/div))}div ref{loadMoreRef}{loading ? 加载中... : 滑动加载更多}/div/div);
};export default InfiniteScroll;适用场景
React Hooks 风格IntersectionObserver 减少性能开销 四、总结
方法适用场景优点缺点原生 touch 事件适用于下拉刷新控制灵活适配广需要手写逻辑scroll 事件上拉加载适用 PC/移动端可能性能开销较大IntersectionObserver ✅推荐上拉加载性能优越简单高效兼容性略低IE 需 polyfillVue/React 方案SPA 项目结合框架特性需要组件化开发 最佳实践
✅ 普通 Web ➝ scroll 事件 防抖✅ 现代 Web ➝ IntersectionObserver✅ Vue/React ➝ 结合 better-scroll 或 useEffect
这样回答面试官会觉得你思路清晰、方案全面绝对加分
103.区分并发和并行
并发Concurrency的概念
在计算机原理中并发Concurrency 是指在同一时间段内处理多个任务但这些任务不一定是同时执行的而是通过任务切换来提高系统的吞吐量和资源利用率。 1. 并发 vs. 并行
并发Concurrency 多个任务在同一时间段内交替执行看起来像是同时运行的。并行Parallelism 多个任务在同一时刻真正同时执行需要多核 CPU。
示例
并发单核 CPU 运行多个任务任务 A 运行一会儿切换到任务 B再切换回来任务交替执行。并行多核 CPU任务 A 在核心 1 上运行任务 B 在核心 2 上运行真正的同时执行。 2. 并发的实现方式
1多线程Multi-threading
一个进程可以拥有多个线程每个线程执行不同的任务。线程可以共享进程的内存提高资源利用率。示例浏览器渲染主线程处理 UI 渲染Worker 线程处理计算任务。
2异步编程Asynchronous Programming
适用于单线程环境如 JavaScript。通过事件循环Event Loop和回调让任务在等待 I/O 时不阻塞其他操作。示例JavaScript 的 Promise、async/await 机制。
3协程Coroutine
轻量级的线程可以在执行过程中手动挂起和恢复。比传统多线程开销更小更适合高并发场景。示例Python asyncio、Go 协程Goroutine 。 3. 并发的挑战
竞争条件Race Condition 多个任务同时访问和修改共享资源可能导致数据不一致。死锁Deadlock 多个任务相互等待对方释放资源导致程序无法继续执行。资源争抢任务切换会带来性能开销如 CPU 线程调度。 4. 并发的应用场景
Web 服务器同时处理多个用户请求数据库管理多个事务并发执行多任务操作系统任务调度前端异步操作React 18 的并发模式 5. 总结
并发 是指多个任务在同一时间段内交替执行提高 CPU 利用率。并行 是指多个任务在同一时刻同时执行需要多核处理器支持。常见并发技术多线程、异步编程、协程等。并发的挑战竞争条件、死锁、资源争抢等问题需要妥善管理。
在前端开发如 React 18中并发模式优化了渲染使得 UI 更新更加流畅也体现了计算机并发原理的实际应用。
104.为什么React中super()和super(props)不传props在子类构造函数中打印props是undefined,在生命周期中打印是正常访问
在 React 类组件中构造函数内 this.props 为 undefined 的根本原因是未将 props 传递给父类构造函数导致父类 React.Component 未能正确初始化 this.props。以下是详细分析 一、现象复现
class MyComponent extends React.Component {constructor(props) {super(); // 未传递 propsconsole.log(this.props); // undefined}
}二、底层原理
1. JavaScript 类继承机制
super() 的作用调用父类构造函数初始化父类属性和方法。参数传递若子类构造函数中调用 super(props)则父类构造函数会接收到 props 参数若调用 super()则父类构造函数接收的 props 为 undefined。
2. React 的 Component 类实现
React 的父类构造函数会接收 props 并初始化 this.props
class Component {constructor(props) {this.props props; // 父类构造函数将 props 赋值给 this.props// ...其他初始化逻辑}
}若调用 super(props) 父类构造函数将 props 赋值给 this.props子类构造函数中可访问。若调用 super() 父类构造函数中 props 为 undefined因此 this.props 未被正确初始化。 三、为什么其他生命周期方法中 this.props 正常
React 在组件实例化后构造函数执行完毕后会再次将 props 挂载到实例上因此
构造函数外如 render、componentDidMountthis.props 由 React 自动注入与 super() 是否传递 props 无关。构造函数内this.props 的初始化依赖父类构造函数的执行因此必须通过 super(props) 显式传递。 四、验证代码
class Parent {constructor(props) {this.props props;}
}class Child extends Parent {constructor(props) {super(); // 不传递 propsconsole.log(构造函数内 this.props:, this.props); // undefined}method() {console.log(方法中 this.props:, this.props); // 正常假设外部手动赋值}
}const child new Child({ name: foo });
child.props { name: foo }; // 模拟 React 的 props 注入
child.method(); // 输出{ name: foo }五、React 源码中的关键逻辑
在 React 的组件实例化过程中即使构造函数中未传递 propsReact 也会在后续步骤将 props 赋值给实例
// React 源码简化逻辑
const instance new Component(props); // 构造函数中可能未正确初始化 this.props
instance.props props; // React 强制覆盖 this.props六、总结
场景super(props)super()父类构造函数正确接收 props初始化 this.props接收 props 为 undefinedthis.props 未初始化子类构造函数内this.props 可用this.props 为 undefined其他生命周期方法this.props 正常this.props 正常由 React 注入
结论在构造函数中访问 this.props 前必须调用 super(props) 确保父类正确初始化。若不需要在构造函数中使用 props可省略 super(props)但 React 仍会在外部注入 this.props。