代码优化是提升网站加载速度和运行效率的核心环节,需要从 “精简体积、减少阻塞、提升执行效率” 三个维度入手,结合前端和后端代码特性制定针对性方案。以下是可直接落地的具体操作方法,附实操示例。
- 删除无效代码:清理注释、空行、重复的 meta 标签(如多个
<meta name="viewport">)、未使用的 class/id;
- 简化 DOM 结构:避免嵌套过深(建议不超过 5 层,如
<div><div><div><div><p>...</p></div></div></div></div>需简化),减少浏览器渲染时的回流(Reflow)成本;
- 使用语义化标签:用
<header><nav><main><footer>替代大量<div>,既减少代码量,又提升解析效率(浏览器对语义标签的解析更高效)。
<div class="header">
<div class="logo">...</div>
<div class="nav">
<div class="nav-item">首页</div>
<div class="nav-item">产品</div>
</div>
</div>
优化后(语义化 + 减少嵌套):
<header>
<div class="logo">...</div>
<nav>
<span class="nav-item">首页</span>
<span class="nav-item">产品</span>
</nav>
</header>
- 合并 + 压缩 CSS:将多个 CSS 文件(如
base.css、home.css、product.css)合并为 1 个,并用工具(如 CSSNano)压缩(去除空格、简化选择器);
- 提取关键 CSS:将首屏渲染必需的 CSS(如导航、Banner 样式)内嵌到
<head>中,非首屏 CSS(如页脚、隐藏模块)通过<link rel="preload">异步加载,避免阻塞页面渲染;
- 优化选择器:避免复杂选择器(如
div:nth-child(2) > .class ~ span),改用简单类名(如.specific-class),浏览器匹配选择器的效率可提升 30% 以上;
- 删除未使用 CSS:通过 Chrome 开发者工具的 “Coverage” 面板(按 F12 → More Tools → Coverage)检测未使用的 CSS 代码,批量删除(如引入的 UI 框架只用到 20% 样式,可剔除 80% 冗余)。
示例:
关键 CSS 内嵌 + 异步加载非关键 CSS:
<head>
<style>
.header { height: 60px; }
.banner { width: 100%; }
</style>
<link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
</head>
- 合并 + 压缩 JS:将多个 JS 文件合并(如
util.js、api.js合并为app.js),并用 Terser 等工具压缩(混淆变量名、删除空格注释);
- 异步加载非核心 JS:对广告、统计、聊天工具等非首屏必需的 JS,添加
async或defer属性,避免阻塞 HTML 解析:
async:下载完成后立即执行(顺序不确定);
defer:下载完成后等待 HTML 解析完毕再执行(按顺序执行);
- 避免全局变量污染:用 IIFE(立即执行函数)或模块(ES6 Module)封装代码,减少全局变量(全局变量会常驻内存,且可能引发冲突);
- 优化 DOM 操作:频繁操作 DOM(如循环中修改元素)会导致多次回流,建议先在内存中构建 DOM 片段,再一次性插入页面:
const list = document.getElementById('list');
for (let i = 0; i < 100; i++) {
list.innerHTML += `<li>Item ${i}</li>`;
}
优化后(内存中构建):
const list = document.getElementById('list');
let html = '';
for (let i = 0; i < 100; i++) {
html += `<li>Item ${i}</li>`;
}
list.innerHTML = html;
- 添加索引:对频繁查询的字段(如用户 ID、订单号、时间)添加索引(如 MySQL 的
ALTER TABLE orders ADD INDEX idx_user_id (user_id)),查询时间可从秒级降至毫秒级;
- 避免全表扫描:杜绝
SELECT * FROM table(尤其大表),只查询需要的字段(如SELECT id, name FROM user);
- 优化 JOIN 操作:多表关联查询时,确保关联字段有索引,且避免关联超过 3 张表(可拆分查询或用缓存);
- 分页查询:对大量数据(如列表页)用
LIMIT分页(如SELECT * FROM articles LIMIT 10, 20),避免一次性加载全部数据。
SELECT * FROM users WHERE register_time > '2023-01-01';
优化后(添加索引 + 限制字段):
ALTER TABLE users ADD INDEX idx_register_time (register_time);
SELECT id, username FROM users WHERE register_time > '2023-01-01';
- 缓存高频查询结果:用 Redis 或 Memcached 缓存数据库查询结果(如热门商品信息、首页数据),设置合理过期时间(如 10 分钟),避免频繁访问数据库;
- 缓存静态资源:对不常变化的页面(如关于我们、帮助中心)生成静态 HTML 文件,用户访问时直接返回静态文件,无需后端动态渲染;
- 避免缓存穿透:对不存在的请求(如查询 ID=-1 的数据),也缓存空结果(设置短过期时间,如 1 分钟),防止恶意攻击耗尽数据库资源。
def get_product(id):
cache_key = f"product:{id}"
product = redis.get(cache_key)
if product:
return json.loads(product)
product = db.query("SELECT * FROM products WHERE id = %s", id)
if product:
redis.setex(cache_key, 600, json.dumps(product))
return product
- 减少循环嵌套:避免多层循环(如 3 层以上
for循环),改用哈希表(字典)查询(时间复杂度从 O (n²) 降至 O (n));
- 复用对象 / 变量:在循环中避免重复创建对象(如
for循环内新建List、Map),应在循环外创建后复用;
- 异步处理非核心逻辑:对非实时需求(如日志记录、数据统计),用消息队列(如 RabbitMQ、Kafka)异步处理,避免阻塞主流程。
List<User> users = ...;
List<Order> orders = ...;
for (User u : users) {
for (Order o : orders) {
if (u.getId() == o.getUserId()) {
}
}
}
优化后(用哈希表优化查询):
Map<Long, List<Order>> orderMap = new HashMap<>();
for (Order o : orders) {
orderMap.computeIfAbsent(o.getUserId(), k -> new ArrayList<>()).add(o);
}
for (User u : users) {
List<Order> userOrders = orderMap.getOrDefault(u.getId(), Collections.emptyList());
}
- 前端构建工具:用 Webpack、Vite 自动完成 JS/CSS 的合并、压缩、Tree-Shaking(删除未引用代码);
- 代码检查工具:ESLint(JS)、StyleLint(CSS)检测冗余代码和低效写法;
- 性能分析工具:Chrome DevTools(前端代码执行时间)、Py-Spy(Python 后端)、Arthas(Java 后端)定位性能瓶颈;
- CDN + 边缘计算:将静态 JS/CSS 部署到 CDN,动态接口用边缘计算节点加速(如 Cloudflare Workers),减少跨地域传输延迟。
- 紧急:压缩 JS/CSS、删除未使用代码、数据库加索引、异步加载非核心 JS;
- 重要:优化 DOM 操作、缓存高频查询、合并文件减少请求;
- 长期:重构低效算法、优化数据库结构、引入性能监控工具。
通过以上方法,代码相关的加载时间可减少 40%-60%,服务器响应速度提升 2-10 倍。 |