【问题标题】:when does setTimeout start executing in a inline <script>setTimeout 何时开始在内联 <script> 中执行
【发布时间】:2017-11-26 11:59:01
【问题描述】:

说我有这样的代码

<html><body>
<bunch of html tags...>
<script>
     function myF()={};
     setTimeout(myF, 100);
</script>
<lots of more html goes here.....></body></html>

据我了解,脚本将在解析 html 时进行评估。但是,在这种情况下,我们有一个 setTimeout,然后是大量的 html 解析。超时时间什么时候可以调用?是否需要等到所有的html解析完成才最终调用myF,还是会在超时事件发生时调用myF,即使还有更多的html解析要完成?

【问题讨论】:

  • The world may never know... 并不是说​​这是一个毫无意义的问题,但如果有人想保证回调何时发生,他们可以使用IIFEdocument.addEventListener('DOMContentLoaded', ...)$(function () { ... });跨度>
  • 超时不会打断当前的“线程”,那不就是等到HTML解析完之后吗?无论如何,您只是出于兴趣而询问,还是出于某种原因它在您的页面上实际上很重要? (在这种情况下,可能有更好的方法来做你正在做的任何事情。)
  • 是的,这对我很重要,是的,可能有更好的方法来做事。

标签: javascript html timeout


【解决方案1】:

不,setTimeout() 不一定一定要等待 DOMContentLoaded

如果是这样,我们就不需要DOMContentLoaded 事件,但如果这还不足以说服您,以下是确凿的证据:

<script>
  window.addEventListener('load', function() {
    alert("Window Loaded");
  });

  document.addEventListener('DOMContentLoaded', function() {
    alert("DOM Content Loaded");
  });

  setTimeout(function() {
    alert(typeof jQuery == 'function' ? 'jQuery Loaded' : 'jQuery Not Loaded');
  }, 15);
</script>
<p>This content will be loaded before jQuery is fetched.</p>
<script>
  document.write('<script src="https://code.jquery.com/jquery-3.2.1.min.js?' + Math.random() + '" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></' + 'script>');
</script>
<script>
  alert('Loaded after <script src="jquery.min.js">');
</script>
<p>This content will not be loaded until after jQuery is fetched.</p>

如果它必须等待DOMContentLoaded,你会看到

Loaded after <script src="jquery.min.js">
DOM Content Loaded
Window Loaded
jQuery Loaded

但是(至少对我而言),大部分时间,输出是

jQuery Not Loaded
Loaded after <script src="jquery.min.js">
DOM Content Loaded
Window Loaded

即使 HTML 的解析是单线程的,但当 &lt;script&gt; 没有 async&lt;link&gt; 必须暂停以分别从 URL 获取资源并执行脚本或样式表时,它会被阻止,这意味着有一个竞态条件DOMContentLoaded 事件和setTimeout(function() { ... }, 15) 之间。

【讨论】:

  • 在使用 DOMContentLoaded 时,您并没有完全测试 OP 的要求。他询问“所有的 html 解析完成”的时间,但浏览器可能会在 解析之后运行超时但 它运行 DOMContentLoaded 事件处理程序时运行超时并非不可想象。
  • @nnnnnn 好的,所以我把我必须的每个引用都切换到document.onDOMContentLoadedwindow.onload,这是相同的答案。那会让你更快乐吗?不管是onload 还是DOMContentLoaded。 OP 询问是否必须等待“直到所有 html 解析完成”,无论我使用哪个事件,答案仍然是“否”。
  • “这会让你更快乐吗?”不。因为那仍在测试 event handlers 的运行时间,而不是解析完成的时间。 (但正如我在问题下评论的那样,如果这对 OP 的代码确实很重要,那么可能有更好的方法来做事。)
  • @nnnnnn 我想你可能会误解这个问题(或者我可能是,但由于我似乎与@Clonkex 在同一页上,我认为不是),但问题是setTimeout 的回调是否必须在解析完成后发生。如果您的论点是 DOMContentLoaded 是错误的事件来表明这一点,而 onload 更正确,那没关系,因为 DOMContentLoaded 总是在 onload 之前发生,而 setTimeout 在之前回调这些事件中的任何一个都会发生。
  • 嗯..我有点明白你的意思,我觉得它非常挑剔,但你的投诉很容易解决,等等。
【解决方案2】:

不要依赖它。 setTimeout 可以这么说并没有创建“中断”,它所做的只是将函数添加到一个队列中,当浏览器决定检查它时检查它。这可能是在线程循环结束时,也可能是在 HTML 解析期间。

进一步阅读 JavaScript 计时器:https://johnresig.com/blog/how-javascript-timers-work/


等待 HTML 完成解析的更好(标准)方法如下:

<html><body>
<bunch of html tags...>
<script>
    function myF()={};
    document.addEventListener("DOMContentLoaded", myF);
</script>
<lots of more html goes here.....></body></html>

或者,使用 jQuery,像这样:

<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<bunch of html tags...>
<script>
    function myF()={};
    $(myF);
</script>
<lots of more html goes here.....></body></html>

【讨论】:

  • @PatrickRoberts 我正在努力确保我的答案是正确的。您对setTimeout 的规则如何实际工作有任何参考吗?我是根据经验回答的,但您的测试似乎表明它可以在解析过程中运行setTimeout
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
  • 2014-05-09
  • 2021-04-15
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多