【发布时间】:2018-04-11 06:01:05
【问题描述】:
见:
https://developers.google.com/speed/docs/insights/BlockingJS
Google 在那里谈论“Render-Blocking JavaScript”,但在我看来,这个术语是不正确、令人困惑和误导的。好像“谷歌”也看不懂了吧?
这一点是 Javascript 执行总是暂停/阻塞渲染,也总是暂停/阻塞“HTML 解析器”(至少在 Chrome 和 Firefox 中)。如果是外部 js 文件,结合异步脚本标签,它甚至会阻止它!
因此,通过例如使用异步来删除“阻止渲染的 Javascript”,意味着也存在非阻塞 Javascript,或者“异步 Javascript 执行”不会阻止渲染,但事实并非如此!
正确的术语是:“渲染阻止下载”。使用 async 可以避免:下载 js 文件,不会暂停/阻止渲染。但是执行还是会阻塞渲染。
另一个例子证实 Google 似乎没有“理解”它。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
</head>
<body>
Some HTML line and this is above the fold
<script>
// Synchronous delay of 5 seconds
var timeWhile = new Date().getTime();
while( new Date().getTime() - timeWhile < 5000 );
</script>
</body>
</html>
我在 Firefox 和 Chrome 中对其进行了测试,它们在 5 秒后而不是在 5 秒内显示(渲染):“一些 HTML 行,这是首屏”!!!!看起来 Google 认为在这种情况下,Javascript 不会阻塞渲染,但正如理论上所预期的那样,它会阻塞。在开始执行 js 之前,所有的 html 都已经在 DOM 中(除了 end body / html 标签),但是渲染还没有完成,将被暂停。因此,如果 Google 真的意识到了这一点,那么 Chrome 会在开始执行 javascript 之前先完成渲染。
如果您采用上面的示例并且您正在使用:
<script src="delay.js" async></script>
或
<script src="delay.js"></script>
而不是内部 javascript。然后它也可以给出与上面示例相同的结果。例如:
- 如果预加载器(扫描已下载的文件)已经下载了“delay.js”,则在“HTML 解析器”出现在 Javascript 部分之前。
- 通常来自 Google、Facebook 等的外部文件已存储在缓存中,因此无需下载,它们只是从缓存中获取文件。
在这种情况下(以及异步),结果将与上面的示例相同(至少在很多情况下)。因为如果没有额外的下载时间,“Javascript 执行”将/可以在前面的 html 完成渲染之前开始。
因此,在这种情况下,您甚至可以考虑在 delay.js 上添加“no-cache”/“no-store”(甚至额外延迟),以使您的页面渲染得更快。通过强制下载(或额外延迟),您将给浏览器一些额外的时间来完成前面的 html 的渲染,然后再执行渲染阻塞 Javascript。
所以我真的不明白为什么 Google(和其他人)使用术语“渲染阻止 JavaScript”,而从理论和“现实生活”示例来看,它看起来像是错误的术语和错误的想法。我看网上没有人讨论这个,所以我不明白。我知道我很聪明(j/k),但我觉得有点奇怪,成为唯一一个有上述想法的人。
【问题讨论】:
-
从您链接到的页面:内联脚本总是被解析器阻塞,除非您编写额外的代码来延迟它们的执行。
-
@JoshLee 但这也不是真的。 Javascript 执行,总是解析器阻塞。如果是异步/同步/延迟也没关系。所以这就是为什么谷歌用他们的信息混淆人们,正如你所看到的,现在你也因为他们的信息而思考错误的方式。您可以使用带有 defer 的外部脚本标记进行我的测试,并且在缓存的情况下(因此没有下载时间):“一些 HTML 行,这在折叠之上”在 5 秒后再次显示,因为在 js 执行期间渲染被阻止!
标签: javascript google-chrome asynchronous rendering render-blocking