使用DOMContentReady被Google认为是一种反模式。

21

一位Google Closure库团队成员断言,等待DOMContentReady事件是一种不好的实践。

简短的故事是我们不想等待DOMContentReady(或更糟的是加载事件)因为它会导致不良的用户体验。在所有DOM从网络加载完毕之前,UI都无法响应。因此,首选方法是尽早使用内联脚本。

由于他们仍然没有提供更多关于这方面的细节,所以我想知道他们如何处理IE中的Operation Aborted对话框。这个对话框是我知道需要等待DOMContentReady(或load)事件的唯一重要原因。

  1. 你知道其他原因吗?
  2. 你认为他们如何处理那个IE问题?

此外,内联JavaScript将JS代码与HTML混合在一起,这对于代码维护和协作来说是非常糟糕的事情。真的是非常奇怪的建议... - BYK
BYK,考虑到Google希望人们使用GWT,这似乎不那么奇怪。Google并不真正关心应用程序的“文档”有多乱,他们只关心从应用程序的每个角落中挤出每一毫秒的时间。对于他们来说,这非常有意义。在其他情况下,可能就不是这样了。 - eyelidlessness
@Marcel Korpel:我本来只是想留下一个简短的评论。但后来我意识到我有更多要说的。 :) 我会把它作为答案发布并删除评论。 - Shripad Krishna
7个回答

29
首先需要解释一下:内联JavaScript的重点是尽早地包含它。然而,这个“可能”取决于DOM节点被声明的情况。例如,如果您有一些需要JavaScript的导航菜单,则应在HTML中定义菜单后立即包含脚本。
<ul id="some-nav-menu">
    <li>...</li>
    <li>...</li>
    <li>...</li>
</ul>
<script type="text/javascript">
    // Initialize menu behaviors and events
    magicMenuOfWonder( document.getElementById("some-nav-menu") );
</script>

只要您只处理已声明的DOM节点,就不会遇到DOM不可用问题。至于IE问题,开发人员必须有策略地包含他们的脚本以防止出现这种情况。这并不是真正的问题,也不难解决。以下是所述的"大问题"的真正问题。
当然,每件事都有优缺点。
优点:
1. 只要将DOM元素显示给用户,通过JavaScript添加的任何功能也几乎立即可用(而不是等待整个页面加载)。 2. 在某些情况下,优点1可以导致更快的感知页面加载时间和改进的用户体验。
缺点:
1. 最差的情况下,您正在混合演示和业务逻辑,在最好的情况下,您正在混合您的

1

内联脚本的最大问题是无法正确缓存。如果您将所有脚本存储在一个js文件中,该文件经过缩小(使用编译器),则浏览器可以为整个站点仅缓存一次该文件。

如果您的网站倾向于繁忙,则从长远来看,这会带来更好的性能。将脚本放在单独的文件中的另一个优点是,您往往不会“重复自己”,并尽可能声明可重用函数。DOMContentReady不会导致不良用户体验。至少它提供了用户所需的内容,而不是让用户等待UI加载,这可能会成为用户的大转折。

此外,使用内联脚本并不能确保UI比使用DOMContentReady时更具响应性。想象一下这样的情况:您正在使用内联脚本进行ajax调用。如果您有一个要提交的表单,那就没问题。如果有多个表单,您最终会重复ajax调用...因此每次都会重复相同的脚本。最终,它会导致浏览器缓存比在DOM准备就绪时分离出来的js文件加载更多的javascript代码。

内联脚本的另一个很大的缺点是需要维护两个独立的代码库:一个用于开发,另一个用于生产。您必须确保两个代码库保持同步。开发版本包含非压缩版本的代码,而生产版本包含压缩版本。这在开发周期中是一个大头痛。您必须手动替换所有隐藏在那些笨重的HTML文件中的代码片段为压缩版本,并且最终希望没有代码出现问题!但是,在开发周期中维护单独的文件,您只需要在生产代码库中用编译后的压缩版本替换该文件即可。
如果您使用YSlow,则会看到:
“使用外部JavaScript和CSS文件通常会产生更快的页面,因为浏览器可以缓存这些文件。内联在HTML文档中的JavaScript和CSS在每次请求HTML文档时都会被下载。这减少了HTTP请求的数量,但增加了HTML文档的大小。另一方面,如果JavaScript和CSS是由浏览器缓存的外部文件,则可以减小HTML文档的大小而不增加HTTP请求的数量。”

我可以保证,只有当代码更改如此频繁以至于将其放在单独的js文件中无关紧要,并且最终与这些内联脚本具有相同的影响时,我才会支持内联脚本。但是,这些脚本不会被浏览器缓存。浏览器缓存脚本的唯一方法是将其存储在带有etag的外部js文件中。

然而,这与JQuery vs Google closure没有任何关系。Closure有自己的优点。但是,闭包库使得所有脚本都放在外部文件中变得困难(虽然并非不可能,但确实很困难)。你只需要使用内联脚本。


2
“浏览器缓存脚本的唯一方式是将其存储在带有ETag的外部JS文件中”这种说法是不正确的:使用Cache-Control: max-age=3155760000可以将文件存储在缓存中很长时间,而无需浏览器重新验证页面(请参见Cache Control Directives Demystified)。如果您在URL中与版本号一起使用此HTTP标头(例如,script.js?v=23),则可以在更改文件时仅递增版本号。另请参见http://developer.yahoo.com/performance/rules.html#etags。 - Marcel Korpel
1
是的,但每次访问新页面时脚本仍需要被缓存,对吧?因此,只有在重新访问页面时才能实现缓存性能优势,但使用外部链接时,全局JS会在每次站点访问时缓存一次。 - Erik Reppen

0
避免使用内联脚本的一个原因是,它要求您在文档中放置任何依赖库之前,这可能会抵消内联脚本的性能提升。我熟悉的最佳实践是将所有脚本(在单个HTTP请求中!)放置在文档的末尾,就在</body>之前。这是因为脚本加载会阻塞当前请求和所有子请求,直到脚本完全加载、解析和执行。
除了魔法棒之外,我们总是不得不做出这些权衡。值得庆幸的是,HTML文档本身越来越成为最少资源密集型的请求(除非您正在做像巨大的data: URL和巨大的内联SVG文档之类的傻事)。对我来说,等待HTML文档结束的权衡似乎是最明显的选择。

0

我认为这个建议并没有真正的帮助。DOMContentReady可能仅仅是因为它当前被过度使用(也许是因为JQuery易于使用的准备事件),才会被视为不好的实践方法。很多人将其用作任何JavaScript动作的“启动”事件。尽管甚至jQuery的ready()事件只是为了用作DOM操作的启动点。

推断来看,页面加载时进行DOM操作会导致糟糕的用户体验!!因为它们是不必要的,服务器端完全可以生成初始页面。

所以,也许闭包团队成员只是想引导人们朝着相反的方向前进,并防止他们在页面加载时进行DOM操作?


页面加载时的DOM操作对于在渐进增强过程中提供不同UI至关重要。例如,考虑可排序列表。完全静态功能的UI将提供向上/向下按钮,这些按钮提交到服务器以重新排序列表。相反,逐步增强的UI可能会提供“夹子”并隐藏这些按钮。这将是尽早加载页面的最佳选择。显然,这个小例子可以通过类切换来简单地完成,但很容易想象它从那里变得更加复杂。 - eyelidlessness
DOM操作包括事件绑定和其他无法在服务器端完成的操作。 - thorn0
1
@eye,@thorn:你们两个都是对的,我在得出结论时有点过于热情了。 - Frunsi

0

如果解析、加载和呈现布局(domready 应该触发的时间点)需要的时间太长,以至于导致明显的 UI 延迟,那么你可能在后端构建页面时出了什么问题,这才是你真正的问题。

此外,在页面末尾之前使用 JavaScript 会阻止 HTML 解析/DOM 评估,直到 JS 被解析和评估。谷歌应该在提供 JavaScript 建议之前先看看他们的 Java。


0
如果你需要自己处理HTML,谷歌的方法似乎非常笨拙。他们使用编译的方法,可以将大脑循环浪费在其他问题上,这是明智的,考虑到他们应用程序的复杂UI。如果你寻找一些更轻松的要求(即:几乎所有其他东西),也许这并不值得努力。
遗憾的是,GWT只能使用Java语言。

-1

这可能是因为谷歌不在乎你是否有Javascript,他们几乎需要它来完成所有的操作。如果你将Javascript作为已经运行的网站的补充,那么在DOMContentReady中加载脚本就可以了。关键是要使用Javascript来增强用户体验,而不是让没有它的用户被隔离。


3
这个问题不是关于是否要在渐进增强中使用JavaScript,而是关于如何实现你正在使用的JavaScript。 - Justin Johnson
2
Justin Johnson,是否以及如何使用“优雅降级”或“渐进增强”这个问题确实会影响您正在使用的JavaScript的实现方式的结果。 - eyelidlessness
3
那么让我重新表述一下。这个问题不是关于增强一个已经工作的网站是否要使用JavaScript或使网站需要JavaScript。@Shawn的答案暗示只有通过使用DOMContentReady才能实现优雅降级,但事实并非如此。渐进增强并不围绕着DOMContentReady或onload事件,而且可以通过内联脚本来实现,同时保持优雅降级。换句话说,优雅降级并不是关于JavaScript,而是关于不使用JavaScript,所以我不认为这个答案适用于原帖或者相关。 - Justin Johnson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接