📜 浏览器厨房的故事:当 defer 和 async 成为你的外卖小哥
—— 如何用异步加载让网页像奶茶一样丝滑
🚦 场景一:饿着肚子等外卖(同步脚本的痛点)
<!-- 老板,我要一份巨无霸汉堡(同步脚本) -->
<script src="heavy-burger.js"></script>
<!-- 等待汉堡送达前,你只能干瞪眼(阻塞渲染) -->
<div id="content">我是无辜的DOM元素,但老板不让我上桌😭</div>
此时浏览器就像个固执的吃货:必须等汉堡吃完(脚本加载执行完毕),才允许其他菜品(DOM渲染)上桌。用户看到的将是一片空白,仿佛在说:"老板,我的网页呢?"
Lighthouse 警告:
⚠️ "Avoid render-blocking resources"
(翻译:你的网页加载速度比树懒还慢!)
🛵 场景二:雇佣外卖小哥(defer vs async)
我们请来两位性格迥异的外卖骑手:
<!-- 骑手A:强迫症患者 defer -->
<script src="cola.js" defer></script>
<!-- 骑手B:闪电侠 async -->
<script src="fries.js" async></script>
两位骑手的秘密任务手册
| 骑手 | 行动模式 | 适用场景 |
|---|---|---|
defer | 1. 接单后立即出发(异步加载) 2. 严格按照接单顺序送货(保持执行顺序) 3. 等所有食材摆好才上桌(DOM解析完成后执行) | 需要保证顺序的套餐(如 jQuery + 插件) |
async | 1. 接单后立即出发(异步加载) 2. 谁先到谁先上桌(加载完立即执行) 3. 可能把薯条倒在沙拉上(执行顺序不可控) | 独立小食(如统计代码、广告) |
🧪 实验时间:模拟骑手配送
<script src="a.js" defer></script>
<script src="b.js" async></script>
<script src="c.js" defer></script>
浏览器后台日志:
[加载开始] a.js、b.js、c.js 同时出发取餐
[加载完成] b.js 最快到达!立即执行(DOM可能还没准备好)
[加载完成] a.js 到达,但坚持要等厨房收拾干净(DOM解析完成)
[加载完成] c.js 到达,默默排在 a.js 后面
[DOM解析完成] 按顺序执行 a.js → c.js
🚀 场景三:React/Vue 厨房的秘密配方
现代前端框架的工程化后厨早已自动化处理脚本加载,比如:
Webpack 大厨的魔法配方
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // 把食材切成小块方便配送
},
},
};
构建后生成的 HTML:
<script src="main.js" defer></script> <!-- 主菜(框架代码) -->
<script src="chunk-vendors.js" defer></script> <!-- 调料包(依赖库) -->
<script src="src_views_Home.js" async></script> <!-- 动态加载的甜点 -->
秘密武器:
preload:提前预约重要食材(关键资源预加载)prefetch:闲时准备可能需要的食材(非关键资源预加载)
🛠️ 手把手改造:优化你的第三方脚本
案例:给网页添加「吃了么」统计代码
<!-- 错误示范:让用户饿着肚子等统计 -->
<script src="https://吃了么统计.com/analytics.js"></script>
<!-- 正确姿势:让闪电侠 async 去送 -->
<script async src="https://吃了么统计.com/analytics.js"></script>
<!-- 高级技巧:异步加载 + 超时保险 -->
<script>
setTimeout(() => {
const script = document.createElement('script');
script.src = 'https://吃了么统计.com/analytics.js';
script.async = true;
document.body.appendChild(script);
}, 3000); // 等用户喝完汤(首屏加载完)再送甜点
</script>
🧠 灵魂总结:选择骑手的黄金法则
- 关键路径脚本(如框架初始化)→
defer(保证顺序不阻塞) - 独立第三方脚本(统计、广告)→
async(谁快谁上) - 巨型资源初始化 → 动态加载 +
Promise(精细控制)
性能优化真言:
"让该快的快(async),让该等的等(defer),让不该存在的消失(删掉冗余脚本)"
🎉 现在,打开你的 Chrome DevTools,到 Performance 面板看看哪些脚本还在「阻塞厨房」吧!浏览器的食客们(用户)正在等待更丝滑的用餐体验~