DOM执行问题的顺序

Jus*_*zer 7 javascript browser domcontentloaded

我在HEAD标记中有一些JavaScript,它在页面上的最后一个脚本(当前已解析)之前动态插入异步加载脚本标记.这个动态包含的脚本标记包含需要在DOM可用之后但在加载所有图像和脚本标记之前解析DOM的JavaScript.重要的是JavaScript在加载所有JS之前开始执行,因为如果有一个悬挂的脚本,这将导致糟糕的用户体验.这意味着我不能等待DOMContentLoaded事件发生.我没有任何灵活性,我放置动态包含脚本标记的JavaScript的第一位.

我的问题是,我是否可以立即开始解析DOM,而无需等待DOMContentLoaded事件?如果没有,有没有办法让我在没有等待DOMContentLoaded活动的情况下这样做?

o.v*_*.v. 1

...HEAD 中的 JavaScript ...在页面上的最后一个脚本之前动态插入异步加载脚本标记 ...

我假设加载程序脚本是内联的,这意味着突出显示的位实际上指的是“当前”脚本元素,即加载程序。发生这种情况是因为只有加载器脚本标记之前的 html 已被解析和解释,因此插入的脚本标记实际上仍在页面中head而不是在页面底部。因此,目标脚本仅限于仅对前面的元素执行 DOM 操作,除非您将代码包装到 DOM 就绪回调中……这正是您首先要避免的!

基本上,您想要加载所有 html 以便页面可见/可扫描,开始加载图像/样式表(发生在非阻塞线程中),然后加载任何 javascript。一种方法是将您的目标脚本放在页面底部,只需正确选择它们的顺序(交互性第一,增强功能第二,第三方分析/社交媒体集成/其他超重的东西最后)并根据您的需求进行调整。从技术上讲,它仍然会阻止页面加载,但无论如何,页面底部只留下脚本(并且由于它们位于底部,因此您可以在加载它们后立即直接操作 DOM,减去一些 IE7 怪癖)。

我想链接到一个相关的咆哮/概述,它提供了不错的例子和一些有关使用和滥用 DOM 就绪回调的计时琐事,以及“故事的另一面”,说明为什么出色的性能可能比健全的依赖管理框架。后者的主题太广泛了,无法在一个答案中穷尽,但是像requirejs 文档这样的东西应该可以让您清楚地了解该模式是如何工作的。

也许需要考虑的另一种模式是构建 SPA - 单页面应用程序,它利用对内容块的异步访问,而不是在完整页面之间进行“传统”导航。该模式带来了被低估但相当显着的性能优势,因为不必在每个页面上解析和重新执行共享的 javascript,这也将解决您对第三方 js 性能的(有效)担忧。毕竟,良好的缓存策略可以显着缩短加载时间,但糟糕的 javascript 代码或大量框架的执行开销仍然存在。

更新:弄清楚了这一点。考虑到您的特定场景(即无法控制标记本身,并且希望成为最后执行的脚本),您应该将异步脚本元素插入 DOM 的操作包装到0mssetTimeout回调中:

setTimeout(function(){

    //the rest is how GA operates
    var targetScript = document.createElement('script');
    targetScript.type = 'text/javascript';
    targetScript.async = true;
    targetScript.src = 'target.js';

    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(targetScript, s);

}, 0);
Run Code Online (Sandbox Code Playgroud)

由于环境的单线程特性,jssetTimeout回调基本上会被添加到队列中,一旦线程不再繁忙,就会延迟 0ms 执行(这里有更彻底的解释)。因此,浏览器甚至不知道需要加载,更不用说执行目标脚本,直到所有“更高优先级”代码完成之后!而且由于 DOM 在添加脚本标记时是可操作的,因此您不必在目标脚本本身中显式检查它(这对于从缓存“立即”加载它时很方便)。