13-前端综合(Fetch · 浏览器调试 · Canvas/SVG · Animations · 性能优化 · 埋点 · CSS · 渲染 · 内存 · 原型链)
一份覆盖前端高频知识点的合订笔记,每个主题独立成节、互不干扰。 适合人群:日常写业务、面试前突击、做性能优化或埋点设计的前端工程师。
一、await fetch() 的两阶段设计
结论
await fetch() 只等待响应头(Headers)返回,不包含完整的响应体(Body)。
设计原理
Fetch API 采用两阶段设计,以提升效率和灵活性。
第一阶段:等待响应头
执行 await fetch(url) 时,JavaScript 会暂停,直到服务器返回 HTTP 状态码和响应头。此时 Promise 变为 fulfilled,你得到一个 Response 对象,其中包含:
status(如 200)okheaders
但响应体的数据流可能还在传输中。
第二阶段:等待响应体
获取 Response 对象后,需要显式调用 response.json()、response.text() 或 response.blob() 等方法来读取响应体。这些方法本身也返回一个 Promise,需要第二个 await 来等待数据流读取和解析完成。
代码示例
async function getData() {
try {
// 第一个 await:等待响应头,获取 Response 对象
const response = await fetch('https://api.example.com/data');
// 此时可以立即检查响应状态
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 第二个 await:等待响应体被完全读取和解析
const data = await response.json();
console.log('数据获取成功:', data);
} catch (error) {
console.error('请求失败:', error);
}
}
这种设计的两大好处
- 快速错误处理:在下载可能很大的响应体之前,就能根据状态码(如 404 或 500)快速判断请求是否成功,节省带宽和时间。
- 流式处理:对于大文件,可以不一次性加载到内存,而是通过
response.body.getReader()分块读取和处理数据流,有效避免内存溢出。
二、Canvas vs SVG:二维码与位图场景
| 维度 | Canvas(位图) | SVG(矢量图) |
|---|---|---|
| 优点 | 性能更强,可利用 WebGL 加速 | 体积小、不失真,可任意缩放 |
| 缺点 | 事件交互处理麻烦(点阵计算),因为没有真实 DOM 节点 | 性能差,无法渲染大数据量 |
| 适用场景 | 大数据量图表、游戏、图像处理、WebGL 加速 | Logo、图标、二维码、矢量插画、需 DOM 操作的图形 |
项目实践:通过 Canvas 生成二维码并下载
iOS 兼容方案: iOS 限制浏览器下载到相册,可将二维码转为图片,长按识别后保存到相册。
💡 一句话选型: 数量级 < 1000 的图标/装饰用 SVG;图表/游戏/图像处理用 Canvas;需要交互(点选/拖拽)首选 SVG(每个元素是真实 DOM,可直接绑事件)。
三、浏览器 Animations 面板:调试动画神器
打开方式
- 打开浏览器控制台 →
Ctrl + Shift + P(macOS:Cmd + Shift + P)→ 输入animate; - 或控制台右上角三个点 → More tools → Animations。
Animations 面板核心功能
1. 时间轴可视化
- 以图形化方式展示当前页面所有正在运行的动画(CSS
@keyframes、transition、Web Animations API)。 - 可直观看到每个动画的 持续时间、延迟、迭代次数、缓动函数(easing) 以及播放状态。
2. 全局播放控制
| 操作 | 快捷方式 | 说明 |
|---|---|---|
| ⏯️ 暂停/恢复 | 顶部按钮 | 一键暂停页面上所有动画,方便逐帧检查中间状态 |
| ⏩ 播放速度调节 | 速度下拉 | 支持 10% / 25% / 50% 慢放,用于精确观察快速动画的细节或排查闪烁问题 |
| 🔁 重播 | 圆形箭头 | 重新触发选中的动画组 |
3. 实时编辑与调试
- 拖拽调整:直接在时间轴上拖动关键帧节点,修改 timing 参数 ,无需反复改代码刷新。
- Easing 曲线编辑:点击贝塞尔曲线图标,弹出可视化编辑器,实时预览缓动效果。
- 同步高亮:鼠标悬停在时间轴的某个动画条上时,页面中对应的 DOM 元素会自动高亮,快速定位动画来源。
4. 录制与分组
- 动画按触发时间自动分组(Group),同一时刻触发的动画归为一组。
- 支持清空后重新录制,避免历史动画干扰调试。
💡 实用场景速查
| 场景 | 操作建议 |
|---|---|
| 动画太快看不清 | 将播放速度调至 10% 或 25% |
| 需要截图 / 检查中间帧 | 暂停动画 → 拖动进度条到目标位置 |
| 对比不同 easing 效果 | 直接点击曲线图标切换预设或自定义 |
| 找不到哪个元素有动画 | 悬停时间轴条目,页面自动高亮对应元素 |
验证 animation-delay | 查看时间轴左侧的空白偏移量是否匹配预期 |
四、前端性能优化方案全景
方案总览:
- 预加载 —
preload/prefetch/preconnect/fetchpriority,精准提速关键资源- 关键 CSS — 首屏样式内联,非关键异步,消除渲染阻塞
- 图片/字体 — 懒加载 + 现代格式 +
font-display,减少首屏下载量- JS 延迟 —
defer/async/ 动态import,根治脚本阻塞- SSR / SSG — Next.js / Nuxt.js,SEO 友好、首屏极快
- 服务端 — Gzip / Brotli、CDN、缓存,传输层提速
- 工程化 — 代码分割 + Bundle 分析 + 监控,持续优化闭环
4.1 预加载
| 关键字 | 用途 | 优先级 |
|---|---|---|
| preload | 当前页关键资源 | 高,立即加载 |
| prefetch | 下一跳资源 | 低,空闲时加载 |
| preconnect | 提前建立域名连接(DNS + TLS) | 中 |
| fetchpriority | 指定关键资源优先级 | 高 / 低 / auto |
<!-- 高优加载首屏必需资源 -->
<link rel="preload" href="core.js" as="script" />
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />
<!-- 提前建立域名连接 -->
<link rel="preconnect" href="https://cdn.example.com" />
<!-- 指定关键资源优先级 -->
<img src="poster.jpg" fetchpriority="high" />
4.2 关键 CSS
首屏样式内联,非关键样式异步加载:
<style>/* 内联首屏关键 CSS */</style>
<link rel="stylesheet" href="all.css" media="print" onload="this.media='all'" />
提取工具:
- Webpack:
critical-css-webpack-plugin - Vite:
vite-plugin-critical - 通用:Critical、Penthouse
4.3 图片 / 字体
| 手段 | 说明 |
|---|---|
| 关键图优先 | 首屏图 preload + fetchpriority="high" |
| 懒加载 | 非首屏图 loading="lazy" 或 IntersectionObserver |
| 现代格式 | WebP / AVIF + srcset 响应响应式尺寸 |
| 字体 | font-display: swap 避免 FOIT,WOFF2 压缩 |
4.4 JS 延迟 / 异步
| 关键字 | 执行时机 | 适用场景 |
|---|---|---|
defer | HTML 解析完、DOMContentLoaded 前执行,不阻塞,按顺序 | 依赖 DOM、需按顺序的脚本 |
async | 加载完立即执行,不阻塞,不保证顺序 | 独立无依赖脚本(统计/广告) |
核心业务 → 内联或高优
组件库、路由 → 动态 import + 代码分割
// 路由级代码分割(React)
const Chart = React.lazy(() => import("./Chart"));
4.5 SSR / SSG
| 模式 | 原理 | 框架 |
|---|---|---|
| SSR | 服务端直出 HTML,首屏极快、SEO 友好 | React → Next.js / Vue → Nuxt.js |
| SSG | 构建时生成静态页,访问秒开 | Next.js / Nuxt / Astro |
加分项:边缘渲染、流式 SSR、渐进式注水。
4.6 服务端与传输
| 手段 | 说明 |
|---|---|
| Gzip / Brotli | 开启压缩,Brotli 比 Gzip 压缩率高 ~20% |
| 103 Early Hints | 替代已弃用的 Server Push 的早期提示机制 |
| CDN | 静态资源就近分发 |
| 缓存 | 强缓存 Cache-Control + 协商缓存 ETag |
4.7 工程化与监控
- 代码分割 — 路由级 / 组件级 / 第三方库拆分
- 打包分析 — Webpack Bundle Analyzer、Rollup Visualizer
- 性能指标 — LCP、FCP、CLS、INP(取代已移除的 TTI 作为交互性核心指标)
- 监控 — Lighthouse、Web Vitals、Performance API
五、埋点体系:三大类型 + SDK 设计
5.1 三大埋点类型速查
| 类型 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 手动埋点(代码埋点) | 业务代码中调用 SDK SDK | 精准可控、支持自定义字段 | 侵入强、改需求要发版 | 支付、登录、转化等核心链路 |
| 无痕埋点(全埋点) | 事件委托 + 冒泡,全局监听自动捕获 | 零侵入、可回溯历史数据 | 数据量大、无法自动带业务参数 | 全量行为采集、全量回溯 |
| 可视化埋点 | 后台圈选 DOM 生成配置,SDK 按配置上报 | 灵活、产品可自助、不用发版 | DOM 结构一变就失效,需约定 data-event-id | 运营活动、快速迭代页面 |
5.2 无痕埋点原理
document.addEventListener('click', ...)全局监听- 事件冒泡捕获所有点击
event.composedPath()拿完整 DOM 路径- 生成唯一标识(页面 + 模块 + 元素),打包上报
- 后台圈选匹配路径,统计行为
🔑 核心思路:先全量采集,后圈选定义事件。
5.3 常用监控指标
| 指标 | 含义 |
|---|---|
| PV | 页面浏览量(刷新 +1) |
| UV | 独立用户(去重) |
| 跳出率 | 只看 1 页就离开的比例 |
| 会话时长 | 单次使用时长 |
| 点击率 | 点击/曝光 |
| 曝光率 | 元素进入视口比例 |
| 转化率 | 完成目标行为占比 |
5.4 SDK 设计要点
事件模型
- 公共字段:用户 ID、设备、时间戳、页面
- 事件字段:类型 + 业务参数
上报策略
- 批量攒发
- 防抖去重
- 失败指数退避重试
- 卸载时
navigator.sendBeacon()保证可达
性能要求
- 不阻塞主线程
- 高频事件(滚动、输入)必须节流
异常捕获
- JS 运行时错误
- 接口异常
- 静态资源加载失败
六、CSS 属性值计算过程(Computed Value)
浏览器把作者样式、默认样式、继承样式,逐步算出最终 Computed 值,决定元素长什么样。
总流程:4 步走完,所有属性必有值
1. 确定声明值 → 2. 层叠(解决冲突) → 3. 继承 → 4. 使用默认值
| 步骤 | 作用 | 关键点 |
|---|---|---|
| 1. 确定声明值 | 收集所有样式声明 | 作者样式 + 浏览器默认样式,无冲突直接采用 |
| 2. 层叠 | 解决冲突,只留一个赢家 | 重要性(含 CSS Cascade Layers @layer)→ 特殊性 → 源码顺序 |
| 3. 继承 | 补上仍无值的属性 | 仅可继承属性(color、font-size 等),优先级低于声明 |
| 4. 使用默认值 | 兑底 | 仍无值则用属性规范初始值 |
逐步骤精讲
① 确定声明值
收集所有作用于当前元素的样式并做基础转换:
| 操作 | 示例 |
|---|---|
| 颜色值转换 | red → rgb(255, 0, 0) |
| 字重转换 | bold → 700 |
| 规则修正 | float: left 强制把 display 转为 block |
② 层叠(核心)
冲突属性按 3 层优先级筛选赢家:
a. 重要性
作者样式(有 !important)> 作者样式(无 !important)> 浏览器默认样式
📌 严格规范还应包括「用户代理
!important」与「用户样式!important」层级,本文速查以作者/默认两者划分。
b. 特殊性(权重)
四位数规则 (内联, ID, 类/属性/伪类, 元素/伪元素),从高位比到低位:
| 选择器 | 权重 |
|---|---|
内联 style="" | 1, 0, 0, 0 |
#id | 0, 1, 0, 0 |
.class / [attr] / :hover | 0, 0, 1, 0 |
div / ::before | 0, 0, 0, 1 |
c. 源码顺序
权重相同,后写覆盖先写。
③ 继承
- 只作用于前两步仍无值的属性,优先级低于声明 /层叠
-仅可继承属性拿父元素的值:
colorfont-sizeline-heighttext-align等
💡 例:
<a>默认有text-decoration,已在声明值阶段确定,不会继承body的none。
④ 使用默认值
前三步仍无值 → 用属性规范的初始值,保证所有属性有值、元素能正常渲染。
调试万能公式
样式不对 → DevTools Computed 面板:
- 看最终值是否符合预期
- 倒推:声明错?权重不够?没继承?被默认样式覆盖?
面试一句话总结
CSS 属性值计算分四步:收集声明 → 层叠解决冲突(重要性 > 权重 > 顺序)→ 继承父元素可继承属性 → 默认值兑底。所有属性最终必有值。
七、重排(Reflow)与重绘(Repaint)
改布局 → 重排(必连带重绘),开销大;只改外观 → 仅重绘,开销小;读布局属性 → 强制立即重排。
对比速查
| 类型 | 含义 | 触发属性 | 开销 |
|---|---|---|---|
| 重排(Reflow) | 几何布局变化,重新计算位置与大小 | width height margin padding top left border font-size line-height | 🔴 大 |
| 重绘(Repaint) | 外观变化、布局不变,只重画像素 | color background border-color opacity visibility box-shadow outline | 🟡 小 |
⚠️ 重排 必连带 重绘;重绘 不一定 触发重排。
触发时机
① DOM 结构变化
增删可见节点、改文本内容、改层级(z-index 不影响布局,不算)。
② 几何属性变化
width / height margin / padding
top / left border / border-width
font-size line-height
display position
③ 读取布局属性(强制同步重排 — 最坑)
浏览器平时将多次 DOM 操作放入队列批量处理;但读取以下属性时必须清空队列、立即重排以返回准确值(即 Forced Synchronous Layout):
| 属性族 | 具体属性 |
|---|---|
| offset | offsetTop offsetLeft offsetWidth offsetHeight |
| scroll | scrollTop scrollLeft scrollWidth scrollHeight |
| client | clientCT clientLeft clientWidth clientHeight |
| 方法 | getBoundingClientRect() getComputedStyle() |
④ 窗口 resize
全局重排。
⑤ 触发重绘的属性
只改外观、不影响布局:
color / background* / border-color / outline
opacity / visibility
box-shadow / text-shadow
代码示例
// ✅ 只触发重绘
box.style.backgroundColor = "blue";
box.style.opacity = 0.5;
// ⚠️ 触发重排 + 重绘
box.style.width = "200px";
box.style.left = "10px";
// ❌ 读布局 → 强制立即重排
console.log(box.offsetWidth);
反模式 vs 优化
// ❌ 读写交错 → 多次强制重排
box.style.width = "200px";
const w = box.offsetWidth; // 强制重排!
box.style.height = w + "px";
// ✅ 先批量读,再批量写 → 一次重排
const w = box.offsetWidth;
const h = box.offsetHeight;
box.style.width = "200px";
box.style.height = h + "px";
八、内存泄漏排查实战
要点
判断泄漏 → 定位原因 → 修复验证。先用 Performance 看趋势,再用 Memory 快照对比定位 Detached DOM、定时器、监听等,并结合框架生命周期清理资源。
排查流程
确认泄漏(Performance)→ 常见原因 → 精准定位(Memory)→ 修复验证
确认是否泄漏
现象: 反复切换路由、开关弹窗、加载列表后,页面越用越卡,内存只升不降。
| 面板 | 操作 | 判断 |
|---|---|---|
| Performance | 勾选 Memory 录制 | 曲线持续上涨、GC 后不回落 → 泄漏 |
| Memory | GC → 快照 → 操作 N 次 → 再快照对比 | 对象只增不减 → 实锤 |
六大常见原因
| # | 原因 | 典型场景 | 根因 |
|---|---|---|---|
| 1 | 定时器未清理 | 卸载未 clearInterval | 回调引用变量 |
| 2 | 事件未移除 | 全局 scroll / resize 未解绑 | 全局引用 |
| 3 | 意外全局变量 | 未声明直接赋值挂 window | 长期占用 |
| 4 | 闭包过度引用 | 长生命周期闭包持 DOM | 阻止 GC |
| 5 | Detached DOM | 删 DOM 但 JS 仍引用 | 游离 DOM 树 |
| 6 | 第三方未销毁 | 图表/地图未 destroy | 外部引用 |
Memory 面板实操
1. 手动 GC → 拍基准快照
2. 重复可疑操作 N 次 → GC → → 拍对比快照
3. Comparison:Detached DOM、Retained Size、Retainer 树
4. 沿引用链定位到组件/定时器/监听
修复与验证
| 问题 | 修复 |
|---|---|
| 定时器 | clearInterval / clearTimeout |
| 事件 | removeEventListener |
| 全局变量 | let / const,勿挂 window |
| 闭包 / DOM | 断引用;WeakMap / WeakSet |
| 第三方 | 调用 destroy() / dispose() |
| 框架 | Vue beforeUnmount;React useEffect 清理 |
修复后重复操作,GC 后内存能回到基线 → 成功 ✅
九、浏览器调试指南
桌面 DevTools、移动端真机、内存泄漏排查合一。以 Chrome / Edge 为主;Firefox / Safari 面板相近,快捷键可能不同。
9.1 总流程
复现问题
├─ 桌面 → 无痕/清缓存 → Console + Network → Sources 断点
│ └─ 性能/内存 → Performance、Memory(见第 八 章)
└─ 仅手机 → USB inspect(优先)或 vConsole + + 代理抓包
9.2 Chrome DevTools
打开方式
| 方式 | Chrome / Edge |
|---|---|
| 快捷键 | F12 或 Ctrl + Shift + I(Mac:Cmd + Option + I) |
| 命令面板 | Ctrl + Shift + P(Mac:Cmd + Shift + P) |
| 元素检查 | 右键 → 检查;或 Ctrl + Shift + C |
面板一览
| 面板 | 主要用途 |
|---|---|
| Elements | DOM、样式、布局、事件监听、无障碍 |
| Console | 日志、表达式、异常栈 |
| Sources | 源码、断点、Snippets、覆盖率 |
| Network | 请求瀑布、Header、复制 cURL |
| Performance | 火焰图、长任务、内存曲线 |
| Memory | 堆快照、泄漏对比 |
| Application | Cookie、Storage、SW、缓存 |
| Lighthouse | 性能 / 可访问性 / SEO 审计 |
| Issues | Mixed Content、Cookie 等问题 |
Sources:断点与单步
| 方式 | 说明 |
|---|---|
| 行号断点 | Sources 点击行号 |
debugger | 执行到此处暂停(勿提交生产) |
| 条件断点 | 行号右键 → Add conditional breakpoint |
| Logpoint | Add logpoint,只打日志不暂停 |
| DOM 断点 | Elements → 节点右键 → Break on … |
| XHR / Fetch | XHR/fetch Breakpoints |
| 事件断点 | Event Listener Breakpoints |
暂停后快捷键:
| 操作 | 快捷键 | 说明 |
|---|---|---|
| 继续 | F8 | 到下一断点 |
| 单步越过 | F10 | 不进函数 |
| 单步进入 | F11 | 进入函数 |
| 单步跳出 | Shift + F11 | 跳出函数 |
| 停用断点 | Ctrl + F8 | 暂不停留 |
其它: Pretty print、Blackbox(跳过 node_modules)、Workspace、Snippets;Ctrl+Shift+P → Coverage 查看 JS/CSS 未使用率。
Console
常用命令:
| 命令 | 说明 |
|---|---|
log / info / warn / error / debug | 分级输出 |
table / dir | 表格 / 展开对象 |
group / groupEnd | 分组 |
time / timeEnd | 计时 |
trace / assert / count | 栈 / 断言 / 计数 |
常用符号:
| 符号 | 说明 |
|---|---|
$0 ~ $4 | Elements 选中节点 |
$_ | 上一条表达式结果 |
$() / $$() | querySelector(All) |
copy(obj) | 复制到剪贴板 |
getEventListeners($0) | 节点监听列表 |
是否阻塞 UI:
| 方式 | 阻塞 UI |
|---|---|
alert() | 是 |
console.* / Logpoint | 否 |
Network
| 技巧 | 说明 |
|---|---|
| Preserve log | 跳转后保留请求 |
| Disable cache | 仅 DevTools 打开时禁用缓存 |
| Throttling | 模拟弱网 |
| 过滤 | domain:、status-code: 等 |
| Copy as cURL / fetch | 右键复制重放 |
| Block request URL | 模拟接口失败 |
| Initiator | 请求触发调用栈 |
Performance
面向前端性能排查与优化;可配合代码中的 performance.mark / measure。内存曲线可勾选 Memory 录制,泄漏对比见 第 八 章。
打开与录制:
| 操作 | 方式 |
|---|---|
| 打开面板 | F12 → Performance 选项卡 |
| 录制 | 点圆形录制 → 操作页面 → 停止 |
| 抓加载全过程 | 点刷新+录制按钮 |
核心指标(一眼抓卡顿):
| 指标 | 说明 |
|---|---|
| FPS | 绿色越高越好,红色 = 掉帧;理想 ≥ 50FPS,一帧约 16.6ms |
| CPU 黄 | JS 执行;长任务 > 50ms 易卡顿 |
| CPU 紫 | 样式/布局;频繁 reflow 要优化 |
| CPU 绿 | 绘制(paint) |
| Main 火焰图 | 横向越长越耗时;标红三角 = long task |
快速步骤:
- F12 → Performance → 录制 → 操作 3~5 秒 → 停止
- 先看 FPS 红块 → CPU 黄/紫是否过长 → Main 里定位 long task
- 点火焰图长任务看调用栈,找到函数后优化
📌 「Ctrl+Shift+E Performance 快捷键」并非官方文档化的固定按键;建议通过命令面板输入 "Show Performance" 打开。
优化方向:
| 方向 | 手段 |
|---|---|
| JS | 拆分长任务、异步化、减少递归 |
| 渲染 | 少改样式触发 reflow;动画优先 transform / opacity |
| 内存 | 勾选 Memory 录制,看堆是否持续走高 |
环境与 Source Map
| 手段 | 说明 |
|---|---|
| 无痕 | Ctrl + Shift + N |
| Hard Reload | 长按刷新 → Empty Cache and Hard Reload |
| Disable cache | Network 面板勾选 |
生产建议 hidden Source Map + 监控平台上传;否则断点对不准打包行号。
实用技巧
| 场景 | 做法 |
|---|---|
| 设备模拟 | Ctrl + Shift + M:视口、DPR、UA、节流 |
| Sensors | 设备栏 → 电量、地理位置 |
| 强制伪类 | Elements → Styles → :hov |
| Overrides | Sources → 本地覆盖线上 CSS/JS |
| 框架扩展 | React / Vue DevTools |
桌面推荐流程
- 无痕或清缓存复现
- Console 看栈 + Network 看失败请求
- Sources:条件断点 / Logpoint + Blackbox
- 接口:Copy as cURL
- 性能:Performance + Coverage;内存异常 → 第 八 章
9.3 移动端与真机
真机 USB / 远程调试
Android + Chrome:
- 开发者选项 → USB 调试
- USB 连接(部分机型选「文件传输」)
chrome://inspect/#devices→ inspect- 无线调试(Android 11+):配对后同列表出现
纯 USB 不强制同一 WiFi;无线或访问电脑局域网 URL 时需同一网络。
iOS + Safari(需 Mac):):
- iPhone:Safari → 高级 → Web 检查器
- Mac Safari:开发 → 选设备与页面
白屏/连不上:更新 WebView/Chrome;检查检查USB授权;注意 HTTPS 与混合内容。
页内控制台(无法 USB)
| 工具 | 说明 |
|---|---|
| vConsole | 轻量,微信 H5 常见 |
| Eruda | Network、Resources 更全 |
| Whistle | 代理抓包、改请求、注入脚本 |
if (import.meta.env.DEV) {
import('vconsole').then(({ default: VConsole }) => new VConsole());
}
抓包与 HTTPS 代理
| 工具 | 平台 | 说明 |
|---|---|---|
| Charles | macOS | 需信任证书;Map Local / Rewrite |
| Fiddler | Windows | HTTP(S) 代理 |
| mitmproxy | 跨平台 | CLI + 脚本 |
| Whistle | 跨平台 | 手机 WiFi 代理到电脑端口(如 8899) |
| Wireshark | 跨平台 | 底层包,较少用 |
HTTPS 须在手机安装并信任代理根证书。
内网穿透
| 工具 | 说明 |
|---|---|
| ngng | 开箱即用 |
| localtunnel | npx localtunnel --port 5173 |
| cloudflared | Cloudflare Tunnel |
| frp | 自建 |
勿长期暴露无鉴权 dev 服务。
微信 / 小程序
| 场景 | 工具 |
|---|---|
| 小程序 | 微信开发者工具、真机预览 |
| 公众号 H5 | vConsole / Eruda 或 Android inspect |
| 企业微信 | 页内控制台 + 抓包 |
移动推荐流程
- 优先 USB →
chrome://inspect或 Safari 开发 - 否则开发环境挂 vConsole / Eruda
- 接口问题 → Whistle / Charles + 手机代理
- 访问本机 dev → 穿透或
电脑IP:端口 - 设备模拟无法替代 WebView、微信内核,须真机验证
9.4 外部资源
| 资源 | 链接 |
|---|---|
| Chrome DevTools 官方 | developer.chrome.com/docs/devtoo… |
| Remote debug Android | developer.chrome.com/docs/devtoo… |
| Firefox Developer Tools | firefox-source-docs.mozilla.org/devtools-us… |
| Safari Web Inspector | webkit.org/web-inspect… |
| vConsole | github.com/Tencent/vCo… |
| Eruda | github.com/liriliri/er… |
| Whistle 代理 | wproxy.org/whistle/ |
十、原型与原型链
10.1 概念
当声明一个函数(一般只有构造函数我们会关注原型);内存中会创建一个对象,每个函数的 prototype 指向这个对象,这个对象即 原型对象(简称原型):
function Person() {}
Person.prototype.fn = function () {}
原型对象的构造器 constructor 指向构造函数本身。
Person.prototype.constructor === Person
10.2 显式 / 隐式原型
- 每一个函数/类均有显式原型
prototype; - 所有实例均有隐式原型
__proto__指向其构造函数的prototype; new实例没有prototype属性,通过__proto__访问到构造函数Person的原型对象。
function Person() {}
const p = new Person()
console.log(p.__proto__ === Person.prototype); // true
值类型没有自己的 __proto__,但它仍可访问 API——因为 JS 引擎会先将它包装为引用类型(装箱),然后触发属性查找。
const obj = {}; // 相当于 new Object()
console.log(obj.__proto__ === Object.prototype);
10.3 原型链
一个对象的 __proto__ 指向它构造函数的 prototype,而 prototype 本身也是一个对象,也会指向它构造函数的 prototype,于是就形成了原型链。
instanceof 的本质是:实例的隐式原型 __proto__ 沿原型链上寻找是否有能匹配的显式原型。
class Person {}
Person.prototype.sayHello = function () {
console.log('hello')
}
class Student extends Person {}
const s = new Student()
子类(Student)的原型对象会创建一个隐式原型 __proto__ 指向父类的原型对象。
Array / String / Boolean 等内置类型的顶层原型最终都指向 Object,而 Object 本身的原型对象(Object.prototype)的 __proto__ 指向 null。
⚠️ 已过时 / 淘汰内容
| # | 内容 | 现状 | 处理建议 |
|---|---|---|---|
| 1 | TTI(Time to Interactive)作为性能指标 | Lighthouse 10(2023)已移除;Web Vitals 自 2024-03 以 INP 取代 FID | 改用 LCP / FCP / CLS / INP |
| 2 | Sensors 面板电量调试 | Battery Status API 已被 Firefox/Safari 移除,Chrome 保留但弃用 | 调试电量场景价值已不大 |
| 3 | Performance 面板「Ctrl+Shift+E」固定快捷键 | 不是官方文档化的固定键 | 用命令面板输入 "Show Performance" |
【存疑】待商榷
- CSS Cascade Layers(
@layer)在「重要性」中的位置:严格意义上@layer介于"重要性"与"权重"之间,本文按速查简化处理;面试需进一步明确。 - Performance 面板「Ctrl+Shift+E」快捷键:本文不做肯定;以实测命令面板为准。