网站性能优化:JS 异步加载与 TLS 全站升级
limitless.net.cn 运行在阿里云成都 ECS(2C/2G/3Mbps),服务器资源有限。近期对网站首页进行了性能分析,发现两个影响加载速度的关键问题:
- 公安备案图标使用 HTTP 协议引用,在 HTTPS 页面中被浏览器作为混合内容(Mixed Content)拦截,导致图片加载失败(部分浏览器)
<head>中多个<script>标签未设置async或defer属性,浏览器必须逐一下载并执行这些脚本后才能继续解析 HTML,造成渲染阻塞
本次优化针对以上两个问题进行了整改。
问题分析
问题一:混合内容导致备案图标加载失败
原代码中,公安备案图标引用的是 HTTP 协议:
<!-- 修改前 -->
<img src="http://www.beian.gov.cn/img/new/gongan.png" alt="公安备案">
由于网站已全站启用 HTTPS,浏览器会拦截页面中的 HTTP 资源请求。用户在页面上看到的是一张裂开的图片,同时浏览器控制台会输出混合内容警告。
问题二:渲染阻塞脚本
浏览器解析 HTML 时遇到 <script src="..."> 标签(不带 async 或 defer),会暂停 HTML 解析,转而下载并执行该脚本。只有脚本执行完毕后,才会继续解析后续 HTML。
这个过程的问题在于:
标红的部分就是用户等待的空白时间。<head> 中有多个这样的脚本时,延迟会叠加。
以首页为例,优化前 <head> 中的脚本加载情况:
| 脚本 | 大小(gzip) | 加载方式 | 是否阻塞渲染 |
|---|---|---|---|
| MathJax (tex-chtml.js) | ~170KB | async | 否 |
| share_current_page.js | ~1KB | 无 | 是 |
| toggle-background.js | ~1KB | 无 | 是 |
| color_egg.js | <1KB | 无 | 是 |
| sidebar_bottom.js | ~1KB | 无 | 是 |
| set_bk_anime.js | <1KB | 无 | 是 |
| backimggene.js | ~5KB | 无 | 是 |
| countdownjs.js | ~1KB | 无 | 是 |
| jQuery | ~30KB | 无 | 是 |
| jQuery-migrate | ~5KB | 无 | 是 |
| mermaid.min.js | ~991KB | 无 | 是 |
其中 mermaid.min.js 体积最大(gzip 后 991KB),在 3Mbps 带宽下下载耗时约 3 秒。在此期间,页面渲染完全被阻塞。
优化方案
改动一:备案图标改用 HTTPS
<!-- 修改后 -->
<img src="https://www.beian.gov.cn/img/new/gongan.png" alt="公安备案">
将协议从 http:// 改为 https://,确保在 HTTPS 页面中正常加载,消除混合内容警告。
改动二:所有 JS 改为 defer 异步加载
将 <head> 中不带 async/defer 的 <script> 标签统一添加 defer 属性:
<!-- 修改前 -->
<script src="./wp-content/themes/fox009-wisdom/assets/js/share_current_page.js"></script>
<script src="./wp-content/themes/fox009-wisdom/assets/js/toggle-background.js"></script>
<script src="./wp-content/themes/fox009-wisdom/assets/js/color_egg.js"></script>
<!-- ... -->
<!-- 修改后 -->
<script defer src="./wp-content/themes/fox009-wisdom/assets/js/share_current_page.js"></script>
<script defer src="./wp-content/themes/fox009-wisdom/assets/js/toggle-background.js"></script>
<script defer src="./wp-content/themes/fox009-wisdom/assets/js/color_egg.js"></script>
<!-- ... -->
为什么选 defer 而不是 async?
async 和 defer 都能让浏览器在下载脚本时不阻塞 HTML 解析,但执行时机不同:
| 属性 | 下载 | 执行顺序 | 执行时机 |
|---|---|---|---|
| 无 | 阻塞解析,下载完执行 | 按代码顺序 | 下载完立即执行 |
async | 不阻塞解析 | 不保证顺序 | 下载完立即执行(可能中断解析) |
defer | 不阻塞解析 | 按代码顺序 | HTML 解析完成后、DOMContentLoaded 之前 |
JS 引擎HTML 解析器浏览器JS 引擎HTML 解析器浏览器defer 模式开始解析 HTML遇到 script (defer)后台下载 JS,不暂停解析继续解析剩余 HTMLHTML 解析完成按顺序执行所有 defer 脚本执行完毕触发 DOMContentLoaded
选择 defer 的原因:
- 保持执行顺序:主题脚本之间存在依赖关系(如多个脚本依赖 jQuery),
defer保证按声明顺序执行 - 不中断渲染:脚本在 HTML 解析完成后才执行,用户能更快看到页面内容
- 兼容性好:所有现代浏览器都支持
defer,包括 IE10+
优化效果
首屏渲染时间
优化前,浏览器在 <head> 中遇到多个阻塞脚本,需要逐一下载执行后才能渲染页面内容。优化后,所有脚本改为 defer,浏览器可以在后台下载 JS 的同时继续解析和渲染 HTML。
混合内容消除
备案图标现在通过 HTTPS 加载,不再被浏览器拦截,页面底部完整显示备案信息。
向后兼容性
defer 属性不影响任何现有 JavaScript 功能:
- 脚本仍然按顺序执行
- DOM 在脚本执行时已就绪(相当于天然包了一层
DOMContentLoaded) - 所有 DOM 操作和事件绑定行为不变
后续优化方向
本次优化解决了最紧急的两个问题,但仍有一些可改进的空间,留作后续迭代:
- mermaid.min.js 按需加载:该文件 gzip 后仍有 991KB,仅在包含 Mermaid 图表的页面需要。可通过 PHP 判断文章内容是否包含
class="mermaid",有条件地加载 - MathJax 按需加载:首页无数学公式,可仅在包含公式标记的页面加载
- 启用 Brotli 压缩:当前仅启用 gzip,Brotli 对文本资源压缩率再高 15-20%
- 静态资源缓存策略:当前
cache-control: max-age=43200(12 小时),对带版本号的静态资源可延长至 30 天 - 页面缓存:WordPress 动态生成 HTML 的 TTFB 约 330ms,使用页面缓存插件可降至 50ms 以内
- 添加 Resource Hints:
preconnect、preload等提示可进一步减少连接建立和资源加载延迟
技术环境
- 服务器:阿里云成都 ECS 2C/2G/40GB ESSD/3Mbps
- Web 服务器:Nginx + HTTP/2 + TLS 1.3
- CMS:WordPress
总结
本次优化通过两个简单改动——HTTPS 链接修复和 JS defer 异步加载——消除了混合内容问题和渲染阻塞问题。改动量小、风险低、效果明确,是性价比很高的性能优化。
性能优化不必一步到位,先解决影响最大的瓶颈,再逐步迭代,是资源受限环境下的合理策略。
本文为 limitless.net.cn 运维笔记系列文章。
limitless网站管理员
2026年8月1日
