广告脚本加async仍阻塞渲染?因async仅适用于无DOM操作、不依赖其他脚本的自包含SDK(如统计代码),而广告初始化常需读写DOM或调用未加载的API,导致报错;正确方案是预加载资源、移至body底部延时执行、用IntersectionObserver按需加载iframe并显式刷新。

广告脚本加 async 属性后仍阻塞渲染?先确认是否真适合 async
不是所有广告脚本都适合加 async。它只对「完全自包含、不读写 DOM、不依赖其他脚本」的脚本安全——比如百度联盟的 cm.js 或 Google Analytics 的统计代码。但如果你的广告初始化逻辑里有 document.getElementById、querySelector,或依赖某个容器元素已存在,加了 async 就大概率报 null 错误。
常见错误现象:BAIDU_CLB_fillSlotAsync is not defined 或容器 div#aside_1 找不到。这是因为脚本执行时 DOM 还没解析完,或广告 SDK 尚未加载就调用了填充函数。
- ✅ 安全用
async:埋点、上报、无 DOM 操作的 SDK(如hotjar.js) - ❌ 禁止用
async:含document.write、动态创建 iframe、调用googletag.display()或BAIDU_CLB_fillSlotAsync的初始化脚本 - ⚠️ 注意:
async对内联脚本无效,只对带src的外部脚本起作用
广告 iframe 必须用 data-src + IntersectionObserver 控制加载时机
loading="lazy" 对广告基本无效:它只对 HTML 中静态书写的 <iframe> 生效,而广告 SDK 返回的 iframe 是 JS 动态插入的,浏览器根本不会识别其 loading 属性。更糟的是,写死 src 可能导致页面一打开就发请求,浪费带宽甚至触发风控。
正确做法是占位 + 监听进入视口再注入真实地址:
立即学习“前端免费学习笔记(深入)”;
- 广告容器写成:
<div class="ad-slot" data-ad-unit="/123/home_top" ></div>,不设iframe,也不写src - 用
IntersectionObserver监听,threshold: 0.2(20% 可见即触发),避免快滑错过 - 触发后手动创建
iframe,设置sandbox="allow-scripts allow-popups"隔离执行环境 - 加载完成必须显式调用广告 SDK 的刷新方法,例如:
googletag.pubads().refresh([slot])或BAIDU_CLB_fillSlotAsync("aside_1")
预加载 cm.js 和 cm.css 能缩短实际加载延迟
浏览器默认不会主动预取广告资源,等脚本标签解析到才发起网络请求,中间有明显等待 gap。在 <head> 顶部加 <link rel="preload"> 可提前启动连接、DNS 查询和 TLS 握手。
实操只需两行:
<link rel="preload" href="https://cpro.baidustatic.com/cpro/ui/cm.js" as="script"> <link rel="preload" href="https://cpro.baidustatic.com/cpro/ui/cm.css" as="style">
注意:as 值必须准确(script / style),否则浏览器可能忽略;路径必须与实际加载的脚本完全一致,包括协议和版本号。
若使用 Webpack/Vite 构建,也可通过 import('./ad-sdk.js') 动态导入,配合 prefetch hint 实现更精细控制。
把广告脚本移到 </body> 前并延迟 300ms 执行最稳妥
即使不用 async,把广告脚本从 <head> 移到 </body> 前,也能避开关键渲染路径。但要注意:不能紧贴着 </body> 放,否则容器 DOM 可能尚未挂载完成。
推荐组合策略:
- 剪切原
<script src="cm.js"></script>,粘贴到</body>闭合标签前 - 在其后立即加内联脚本:
setTimeout(() => BAIDU_CLB_fillSlotAsync("aside_1"), 300) - 确保对应容器(如
<div id="aside_1"></div>)已在 HTML 中静态声明,而非 JS 动态创建 - 禁用任何
window.onload或DOMContentLoaded包裹,它们会进一步延迟广告触发
这个 300ms 是经验值:足够让 DOM 解析完毕,又不至于让用户等太久;太短(如 0ms)仍可能取不到元素,太长(如 1000ms)影响首屏广告曝光。



















