本节摘要:性能优化是回到 1.3 节的加载流水线逐段提速:网络段减请求数与传输量,渲染段减少布局返工,脚本段别堵主线程。铁律是先测量再优化、改完复测——本节用网络面板给看板建立性能基线,逐项优化后再刷新成绩单,每个数字的变化都有出处。
优化最大的陷阱是凭感觉改——感觉慢就压缩图片、感觉卡就删动画,改完不测,效果全靠信仰。正确顺序永远是:测量、定位瓶颈、改动、复测。测量工具就是 1.4 节认识的网络面板:清缓存重载,看每个文件的体积与耗时,看关键时间节点——首字节到达、首批内容绘制、可交互就绪。看板的初次成绩单:文档很瘦,但页头背景图占了全部传输量的大头、脚本阻塞了文档解析、图片没有尺寸引发布局跳动。三个病灶,逐个治。

网络段的目标是让"渲染要用的东西"尽早到货,让"暂时用不上的东西"别抢道。三条手段按收益排序:压缩体积(页头背景图从数兆压到数百K,视觉差异肉眼难辨)、延迟加载(屏外图片滚到附近才发起请求)、缓存复用(静态资源配好缓存策略,回头客零传输)。
<!-- 网络段优化落地:三处改动 --> <link rel="stylesheet" href="board.css"> <!-- 样式表在头部且只有一份:渲染的关键材料优先到货 --> <img src="workshop-line3.jpg" alt="三号产线晨检" width="320" height="180" loading="lazy"> <!-- 懒加载:滚到视口附近才取图;宽高写全:布局一次成型不跳动 --> <script type="module" src="board.js"></script> <!-- 模块脚本默认不拦解析:文档先读完整,脚本随后执行 -->
复测成绩单(网络面板对照): - 传输总量:降约八成(大图压缩 + 懒加载延后) - 首批内容绘制:提前——文档与样式表即齐即画,不等图片 - 请求数:首屏减,滚动时按需增——总量换体验,划算 - 重复访问:静态资源走缓存,二次访问近乎秒开
渲染段的优化在 1.3 节的流水线图上做过伏笔,此处兑现。三条:几何信息前置(图片尺寸写结构里,布局不返工)、别让首屏等齐所有资源(骨架与文字先上,装饰后补)、动画只动合成层属性(3.5 节黄金律)。脚本段的改树也有讲究:读写分离——先把要读的尺寸一次读完,再统一写入改动,避免"读一次写一次"的交替触发反复重排。
// 读写分离:避免布局抖动的经典手法 // 反面(读写交替,每轮都触发重排): for (const row of rows) { const h = row.offsetHeight; // 读:强制布局结算 row.style.height = h + 4 + "px"; // 写:作废刚才的结算 } // 循环几轮就结算几次——页面发抖 // 正面(先读尽、再写尽): const heights = rows.map((r) => r.offsetHeight); // 读:一轮读完 rows.forEach((r, i) => { r.style.height = heights[i] + 4 + "px"; }); // 写:一轮写完——布局只在两轮之间结算一次
// 长任务切片:统计大清单别堵主线程 function chunkedSummarize(orders, onDone) { const chunk = 500; // 每批处理五百条 let i = 0; function step() { const end = Math.min(i + chunk, orders.length); for (; i < end; i++) { /* 累计这一批 */ } if (i < orders.length) { setTimeout(step, 0); // 让出主线程:下一批排到队尾 } else { onDone(); // 全部完成 } } step(); } // 效果:十万条工单的统计不再冻住点击—— // 批间让出,用户操作随时插队
性能有两个时钟:客观时钟(毫秒数)与感知时钟(用户觉得久不久)。优化感知的手段常被轻视,却性价比极高:骨架屏(数据未到先画灰块占位,加载有了进度感)、渐进呈现(先表格后徽章动画)、乐观更新(点推进先变样式、后台再落数据,失败再回滚)。看板接入乐观更新后,操作工的"点了没反应"投诉直接清零——客观时间没变多少,感知时间大幅缩短。
// 乐观更新:先响应、后对账 async function advanceOptimistic(no) { const prev = orders.find((o) => o.no === no); const next = { ...prev, status: NEXT[prev.status] }; orders = orders.map((o) => (o.no === no ? next : o)); renderOrders(orders); // 第一步:立即上屏 try { await pushToServer(next); // 第二步:后台同步 } catch { orders = orders.map((o) => (o.no === no ? prev : o)); renderOrders(orders); // 第三步:失败回滚 showErrorBar("网络不稳,刚才那步已撤销"); } }
单次优化会退化,纪律要靠预算固化:给看板定几条硬指标——首屏传输不超某值、图片单张不超某值、长任务不超某毫秒、交互响应不超某毫秒。每次迭代提交前对照预算跑一遍,超标就修,修不动就把预算项议价。预算的本质是把"性能很重要"翻译成可执行的数字——没有数字的重视都会在赶工时第一个被牺牲。
⚠️ 常见坑:过度优化。给只有几十条数据的看板上虚拟滚动、给静态页上缓存服务、给一次性的内部工具压榨最后几十毫秒——优化的投入要对得起收益,预算超标才动手,指标健康就收手。
💡 关键直觉:性能优化的顺序应该是"先问为什么慢,再问怎么变快",而"为什么慢"的答案九成在测量工具里,不在猜测里。养成"开口先报数"的习惯,你的优化建议才有说服力。
提速完成,最后一道工序上锁:安全防线,堵住注入与伪造。