一说优化性能,很多人第一反应是”上缓存插件””换 CDN””压缩图片”。这些都对,但顺序容易搞错。
我把主题能管的部分拆成三个问题,按影响从大到小排:
这三个里,第一个影响最大——因为它是”卡住”,不是”慢一点”。
我原来的 header.php 是这样的:
<head>
<link rel="stylesheet" href=".../bootstrap.min.css">
<link rel="stylesheet" href=".../style.css">
<script src=".../jquery.min.js"></script>
<script src=".../bootstrap.min.js"></script>
</head>
那两个 <script> 干了一件坏事:浏览器读到它们,会停下来下载、停下来执行,然后才继续往下解析 HTML。
你在手机上打开这个页面,看到的顺序是:白屏 → 下载 jQuery(几十 KB)→ 执行 → 下载 bootstrap → 执行 → 才开始画页面。
用户在前一秒多里看到的是白的。
改法很简单,加一个属性:
<script defer src=".../jquery.min.js"></script>
<script defer src=".../bootstrap.min.js"></script>
defer 的意思是:”你可以先下载,但别急着执行,等 HTML 解析完了再按顺序执行。”
这一改,浏览器就能一边下载脚本、一边继续解析页面,首屏不再等它。
两个属性长得像,作用完全不同:
| 属性 | 下载 | 执行时机 | 适合什么 |
|---|---|---|---|
| 不加 | 立即,阻塞解析 | 下载完立刻 | 几乎没有 |
async |
并行,不阻塞 | 下载完就执行,顺序不定 | 完全独立的统计、广告脚本 |
defer |
并行,不阻塞 | HTML 解析完,按书写顺序 | 有依赖关系的库(jQuery → 插件) |
关键区别:async 不保证顺序,defer 保证顺序。
我的 bootstrap 依赖 jQuery,如果两个都用 async,有可能 bootstrap 先下载完先执行——那时 $ 还不存在,控制台报错「$ is not defined」,整个交互全废。
所以:有依赖的,一律用 defer。
这个问题我踩过。
脚本改成 defer 之后,它执行的时间点变成了”HTML 解析完之后”。如果页面里有一段内联脚本,在 HTML 中间就调用了 $(...),那它执行的时候 jQuery 还没到,直接报错。
我改完之后干的第一件事,是打开手机点了一下汉堡菜单。
为什么要专门测这个?因为那个菜单的展开靠 bootstrap 的 JS。如果脚本没加载成功,菜单按钮点了没反应——而桌面端看不出问题(桌面端菜单是横向展开的,不依赖 JS)。
测的时候一定要用手机,或者把浏览器窗口拉窄。
如果真出问题,两个解法:
defer 或者挪到页面底部;defer,把 bootstrap 放回原位。我另一个站上有个真实的例子:一张封面图,原图 2560×2560,334 KB。而它在页面上显示的宽度是 560px。
多下载了 4 倍多的像素,用户一点都看不出来。
WordPress 上传图片时会自动生成多个尺寸(thumbnail / medium / large),主题要做的是用对尺寸,而不是永远用原图。
三个具体做法:
一、用 the_post_thumbnail() 而不是自己拼 <img>
<?php the_post_thumbnail( 'medium', array( 'loading' => 'lazy' ) ); ?>
传 'medium',WordPress 就会自动输出 srcset(一组不同宽度的候选图),浏览器按自己的屏幕宽度挑一个。这一行代码,比手动压缩一百张图都管用。
二、首屏之外的图加 loading="lazy"
<img src="..." alt="..." loading="lazy">
浏览器会等图片快进入视口了才开始下载。文章页正文里的图,全都该加。
三、首屏那张图别加 lazy
这条容易被忽略:lazy 是”推迟加载”,而首屏图是”马上就要看”的。给它加 lazy,等于让浏览器先犹豫一下再下载,反而更慢。
首屏图要么不加,要么用 fetchpriority="high" 提示浏览器优先下载。
每多一个文件,就多一次”请求—等待—响应”的往返。移动网络下,一次往返可能就是 100 毫秒。
主题层面能做的:
style.css;remove_action 掉。最后这条我实测过:清理前首页 gzip 后 9930 字节,清理后 7953 字节,降了 20%。而且清理掉的东西(区块库 18.5 KB)里,我一个字都没用过。
<link rel="dns-prefetch" href="//hm.baidu.com">
这行告诉浏览器:”我等下可能会连这个域名,你可以先把域名解析做了。”
它只省几十毫秒,但成本是一行代码。凡是页面里会加载的第三方域名,都值得加一行。
三个常见但没好处的”优化”:
一句话记住:先解阻塞(defer),再减体积(图片尺寸),最后减请求(删无用资源)。顺序反了,效果差一半。
下一篇聊缓存——为什么你改完代码,访客看到的还是旧的。