首页 文章

DOM执行问题的顺序

提问于
浏览
7

我在 HEAD 标记中有一些JavaScript,它在页面上的最后一个脚本(当前已解析)之前动态插入异步加载脚本标记 . 这个动态包含的脚本标记包含需要在DOM可用之后但在加载所有图像和脚本标记之前解析DOM的JavaScript . 它等待 DOMContentLoaded 事件触发 . 我没有任何灵活性可以放置动态包含脚本标记的第一部分JavaScript .

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

4 回答

  • 1

    我强烈建议您完整阅读以下文章,该文章详细探讨了脚本加载和实际DOM准备情况的秘密,何时可以安全地使用什么做,同时还要考虑浏览器的不一致 .

    http://www.html5rocks.com/en/tutorials/speed/script-loading/

  • 0

    以下技术的行为使得解析DOM安全...

    • 使用窗口加载或DomContentLoaded事件

    • 在页面底部声明或注入脚本

    • 在脚本标记上放置"async"属性

    • 或这样做:

    <script>

    的setTimeout(函数(){
    //在这里声明的脚本将在解析DOM后执行
    },0);
    </ SCRIPT>

    此外,这些将在DOM中加载页面 .

    在任何DOM下面声明脚本时,无需调用DomContentLoaded事件,除非您需要进行大小计算或定位,因为如果未指定宽度/高度,图像/视频将改变事物的大小 .

    以下是一些可行的方案 .

    依赖DOM以上

    <script src =“jquery.js”> </ script> <SCRIPT> $( 'MYDOM')了slideDown( '快') . </ SCRIPT> 或试试这个: > <script> //不会放屁 setTimeout(function(){console.log(document.getElementById('mydom') . innerHTML);},0); </ SCRIPT> 相关DOM低于或低于(不要) 这是我的小测试,你看到setTimeout工作是我直到最近才注意到的那些奇怪的事情之一所以很高兴看到它的一个有用的例子 . [http://jsfiddle.net/FFLL2/](http://jsfiddle.net/FFLL2/)

  • 0

    是的,您应该等待用户代理告诉您DOM已加载 . 但是,有多种方法可以做到这一点 .

    onreadystatechange to interactiveDOMContentLoaded 之间存在差异 .

    根据http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html,用户代理在停止解析文档后所做的第一件事就是将文档准备就绪设置为"interactive" .

    用户代理不会等待加载脚本 .

    当文档就绪状态发生变化时,用户代理将在Document对象上触发readystatechange .

    因此,如果您担心的脚本是非内联的,那么您可能会与readystatechange挂钩 .

    谈论跨浏览器:这是规范 .

  • 1

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

    我假设the loader script is inline,意味着突出显示的位实际上是指"current"脚本元素,即加载器 . 发生这种情况是因为只解析并解释了加载器脚本标记之前的html,因此插入的脚本标记实际上仍然在 head 中而不在页面的底部 . 因此,目标脚本仅限于对前面的元素执行DOM操作,除非您将代码包装到DOM准备好的回调中......这是您首先要避免的!

    基本上你想加载所有的HTML,以便页面可见/可扫描,开始加载图像/样式表(发生在非阻塞线程中),然后加载任何JavaScript . 一种方法是put your target script at the bottom of the page,只需正确选择他们的订单(首先是交互性,第二次增强,第三方分析/社交媒体集成/其他任何超重的最后)并根据您的需求进行调整 . 技术上it still blocks the page load,但是页面底部只留下了脚本(因为它们位于底部,你可以在加载DOM时直接操作DOM,减去一些IE7怪癖) .

    有一个相关的rant/overview我喜欢链接到它提供了不错的示例和一些关于使用和滥用DOM就绪回调的时间琐事,以及"other side of the story"为什么恒星性能可能比一个理智的依赖管理框架更低的 Value . 后者的主题太广泛而不能在一个答案中用尽,但像requirejs documentation这样的东西应该让你对模式的运作方式有一个很好的了解 .

    也许另一种需要考虑的模式是构建一个SPA - 单页面应用程序,它利用对内容块的异步访问,而不是在完整页面之间导航"traditional" . 该模式伴随着not having to parse and re-execute shared javascript on every page低估但相当重要的性能优势,这也将解决您对第三方js性能的(有效)担忧 . 毕竟,只是a good caching policy会创造奇迹加载时间,但糟糕的JavaScript代码或大量框架的执行开销仍然存在 .

    Update: 想出来了 . 考虑到您的特定方案(即无法控制标记本身,并希望成为最后一个执行的脚本),您应该将异步脚本元素的插入包装到一个0ms setTimeout 回调中:

    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);
    

    由于环境的单线程特性,一旦线程不再忙,js setTimeout 回调基本上被添加到队列中0ms延迟执行(more thorough explanation here) . 所以浏览器没有从缓存中加载"instantly" .

相关问题