【问题标题】:defer scripts and execution order on browsers推迟浏览器上的脚本和执行顺序
【发布时间】:2015-09-05 12:54:08
【问题描述】:

我一直致力于为我的一个项目的 HEAD 部分中使用的外部脚本添加 defer 属性。我查询了多个延迟脚本标签的执行顺序。

以下是我的观察,这将有助于我们更好地理解我的查询:

根据http://www.w3.org/TR/html5/scripting-1.html

defer 属性存在,然后在页面完成解析时执行脚本

defer 属性确实有效。但是,我对执行顺序持怀疑态度。在 FF 和 Chrome 上似乎有所不同。

根据我的项目:

<script defer="defer" src="{SERVER_PATH}/deps.js?1441452359"></script>
<script defer="defer" src="{SERVER_PATH}/script1.js?1440067073"></script>
<script defer="defer" src="{SERVER_PATH}/script2.js?1441451916"></script>

在这里,deps.js 是大约 120kb(gzipped)的巨大文件,而 script1-3 是 20-50kb(gzipped)的常规大小。

在 Firefox 上,延迟脚本的执行确实按出现的顺序开始,但不会以相同的顺序完成。而在 chrome 上,除非前一个脚本完成执行,否则下一个脚本的执行不会开始。看起来 Chrome 是有道理的。

为了测试执行顺序,我在每个脚本的第一行和最后一行插入了 console.log,例如在 deps.js 中

console.log("Execution Start: deps");
// minified deps script content.
console.log("Execution End: deps");

在 Firefox 上的控制台输出下方:

Execution Start: deps
Execution Start: script1
Execution Start: script2
// Script Error as script1 needs deps to render completely.
// Script Error as script2 needs deps to render completely.
Execution End: deps

在 Chrome 上的控制台输出下方:

Execution Start: deps
Execution End: deps
Execution Start: script1
Execution End: script1
Execution Start: script2
Execution End: script2

但是,FF 上的行为并不总是如上所示。有时它确实像 Chrome 一样工作。它看起来像是一个仅限 Firefox 的问题。或者,可能是因为 deps.js 文件太重且被缩小并且需要时间来渲染。

任何有类似经验的人可以帮助我吗?如果需要任何其他信息,请告诉我。

PS:其他解决方案,例如,移动页面底部的脚本不是我目前正在考虑的事情。

【问题讨论】:

  • 当您延迟文件时,保证它们(如果在浏览器中正确实现)按照它们出现在元素上的顺序执行。我最喜欢的问题解释:growingwiththeweb.com/2014/02/async-vs-defer-attributes.html
  • @NinoŠkopac 我同意你的看法。他们应该按顺序执行。但是 FF 有时似乎表现不同,执行开始顺序相同,但执行结束顺序不同。相同的实现在 Chrome 上运行良好。奇数。
  • 你用的是最新版的FF吗?
  • 我在 Android 上的 Firefox 42.0.1 中看到了这个问题,并发现了这个 Mozilla 错误报告:bugzilla.mozilla.org/show_bug.cgi?id=1212696
  • 看起来有点疯狂,因为假设同步执行,其他一些脚本不可能在已经开始的脚本结束之前开始执行。如果是这种情况,则意味着 FF 执行了一些无论如何都不应该发生的多线程。你能确认你的开始和结束日志安排在同一个事件循环中工作吗?

标签: javascript html


【解决方案1】:

HTML5.0 规范是这样说的:

如果元素有src属性,并且元素有defer属性,并且元素已经被标记为“parser-inserted”,并且元素没有async属性

该元素必须添加到脚本列表的末尾,当文档完成与创建该元素的解析器的文档相关联的解析时将执行该脚本。

一旦获取算法完成,网络任务源放置在任务队列中的任务必须设置元素的“准备好被解析器执行”标志。解析器将处理执行脚本。

所以它确实说它推迟脚本执行直到关联的Document 被解析,它还说它被推到列表中。所以列表的顺序应该是被解析插入的脚本顺序。

但是,第二部分让我担心。它基本上说它只会被标记为执行,直到网络任务完成下载脚本。然后...“解析器将处理执行脚本”。

我在规范中找不到的是文档解析后脚本执行的情况。当脚本“准备好被解析器执行”时,它是否继续按列表顺序执行脚本?还是会等到列表中的所有脚本都“准备好被解析器执行”后再执行它们。

规范(第 15 步):http://www.w3.org/TR/html5/scripting-1.html#script-processing-src-prepare

【讨论】:

  • 听上去确实是按顺序执行的。如果它等待全部下载或不等待可能只是实现定义,并且除非需要订购而不等待可能是更好的实现?
  • 我同意这很可能是更好的实现。当我写这个答案时,只是暗示浏览器之间可能存在不同的行为,因为它们是如何执行的。尽管很可能并非如此。
【解决方案2】:

我想说,除非“执行结束”日志发生在与“执行开始”日志不同的事件循环中,否则这是不可能的。

你能确保我们做到这一点吗?否则,这意味着 Firefix 在这里做了一些多线程处理,而我们知道,JS 对此不支持。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 2012-08-20
    相关资源
    最近更新 更多