DOMContentLoaded和load事件的区别

364

DOMContentLoadedload事件有什么区别?


8个回答

265

来自Mozilla Developer Center

DOMContentLoaded事件在文档已经完全加载和解析之后被触发,不用等待样式表、图像和子框架完成加载(可以使用load事件检测完全加载的页面)。


41
请注意,同样的MDN链接现在也说:“注意:样式表的加载会阻塞脚本执行,因此如果你在<link rel="stylesheet" ...>后有一个<script>,页面将无法完成解析 - DOMContentLoaded也将不会触发 - 直到样式表被加载。” - Nick
11
@Nick 这个页面给出了原因。http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/ 不过我建议你观看页面上的视频。 - abhisekp
1
@abhisekp 不错的教程,尽管那个视频链接现在已经过时了。 - supi
1
因此,渲染树是在DOMContentLoaded触发后构建的。但是根据https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event的说法,DOMContentLoaded不会等待图像/子资源/子框架完成加载。您知道这些图像/子框架/子资源是否在渲染树构建后被调用,还是它们在渲染树仍在构建时就已经被DOM树调用了?换句话说,渲染树是否触发了一堆连接来下载这些图像/子框架/子资源,还是它们的下载已经在进行中了? - weefwefwqg3
1
@Onkeltem 啊,但 A 的定义包括最后 B 所做的内容。 - Simon Lieschke
显示剩余2条评论

114
< p > DOMContentLoaded事件将在DOM层次结构完全构建后立即触发,load事件将在所有图像和子框架加载完成时执行。

DOMContentLoaded适用于大多数现代浏览器,但不包括IE,包括IE9及以上版本。有一些解决方法可以在旧版本的IE上模拟此事件,例如使用jQuery库上使用的IE特定的onreadystatechange事件。


7
“这个事件”是指你所提到的哪一个事件? - Tom Hubbard
3
“这个事件” = DOMContentLoaded。它在IE8上无法正常工作。如果需要支持它,请使用CMS链接提供的解决方法。 - Jan Derk

63

自行体验差异:

演示

来自 Microsoft IE

当当前页面解析完成时,DOMContentLoaded事件会触发;而所有文件都从所有资源中(包括广告和图片)加载完毕后,load事件才会触发。DOMContentLoaded是一个很好的事件,可用于将UI功能与复杂的网页连接起来。

来自Mozilla开发者网络

当文档完全加载并解析完成时,DOMContentLoaded事件会被触发,无需等待样式表、图像和子框架完成加载(可以使用load事件检测完全加载的页面)。


2
DOMContentLoaded 保证所有脚本(包括 defer/async)都已加载完毕吗?这里并没有提到脚本:developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded - Serg
@Sergey 不是这样的。异步资源 - 即 <script async src=app.js/> - 是独立于页面其余部分加载的,因此 DOMContentLoaded 可能会在资源从服务器获取之前触发。 - Mehrad Sadegh
2
@MehradSadegh 我认为你错了!根据MDN文档带有defer属性的脚本将阻止DOMContentLoaded事件触发,直到脚本加载并完成评估。 您可以查看这个SO问题,以确认它:https://dev59.com/mlgQ5IYBdhLWcg3wUiVS - radzak
1
@Jatimir 我认为defer和async属性具有不同的行为。 - Mehrad Sadegh
@MehradSadegh 你是对的,我很抱歉,由于某种原因我以为你在提到 defer。我的错 :) - radzak
1
@Jatimir 很高兴你还是发了帖子,因为你的贡献正是我所需要的!谢谢! - Robert Wildling

32

DOMContentLoaded 等同于 window.onDomReady()

Load 等同于 window.onLoad()

在文档“准备就绪”之前,页面不能安全地进行操作。jQuery为您检测到了这种就绪状态。$(document).ready() 中的代码将只在页面文档对象模型(DOM)准备好执行JavaScript代码时运行一次。$(window).load(function() { ... }) 中的代码将在整个页面(包括图像或iframe),而不仅仅是 DOM 准备就绪时运行一次。

参见:使用JQuery Core的document-ready文档


6
问题不是关于jQuery。 - Sam Hobbs
7
并不是必须的,但理解起来会有所帮助。 - Anderson
1
没有 window.onDomReady() 这样的东西。 - T S

23
为了全面理解,建议阅读以下文章:
  1. 什么是DOM和CSSOM: https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model
  2. 什么是渲染树: https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction
  3. 所有关于DOMContentLoaded、load和首次打印的相关内容: https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp
简而言之: 当DOM创建完成(关于DOM的更多信息请参见链接1)时,将触发DOMContentLoaded事件,当DOM、CSSOM和所有其他资源加载完成时,将触发load事件。如果没有JavaScript,那么您的网页加载顺序可能如下所示: enter image description here 或者用检查窗口的话来说,DOMContentLoaded事件将比load事件提前很多(蓝线表示DOMContentLoaded,红线表示load事件): enter image description here 然而,如果您使用的是JavaScript(不是async或defer),则DOM创建将等待JS加载。由于JS还修改CSS,因此JS将等待CSSOM加载。
由于这是最常见的情况,因此在大多数情况下,DOMContentLoaded事件的创建实际上也必须等待样式表加载完成。
然后,加载链如下所示:

enter image description here

因此,DOMContentLoadedload的主要区别在于,仅涉及图像的加载时间,在此情况下,图像可以与样式表和JS并行下载。

enter image description here

请注意,如果您在JS中使用async或defer,则不会发生这种情况:

enter image description here


18
  • domContentLoaded:标志着DOM已准备就绪,没有阻塞JavaScript执行的样式表 - 这意味着我们现在可以(可能)构建渲染树。许多JavaScript框架在开始执行其自身逻辑之前等待此事件。因此,浏览器捕获EventStart和EventEnd时间戳,以便我们跟踪此执行所花费的时间。

  • loadEvent:在每个页面加载的最后一步骤中,浏览器会触发“onload”事件,该事件可以触发其他应用程序逻辑。

来源


如果我有任何带有指向JS的URL的脚本标签,它们会在domContentLoaded之前还是之后加载? - Pavan

2
这是我们使用的一些代码。我们发现MSIE对于DomContentLoaded有时有效,有时无效,在没有其他资源缓存时会出现一些延迟(根据我们的控制台日志最多达到300毫秒),而在它们被缓存时触发得太快。因此,我们为MISE提供了一个备用方案。您还希望在外部JS文件之前或之后触发doStuff()函数。
// detect MSIE 9,10,11, but not Edge
ua=navigator.userAgent.toLowerCase();isIE=/msie/.test(ua);

function doStuff(){
    //
}
if(isIE){
    // play it safe, very few users, exec ur JS when all resources are loaded
    window.onload=function(){doStuff();}
} else {
    // add event listener to trigger your function when DOMContentLoaded
    if(document.readyState==='loading'){
        document.addEventListener('DOMContentLoaded',doStuff);
    } else {
        // DOMContentLoaded already loaded, so better trigger your function
        doStuff();
    }
}

1

在Chrome 80+的高版本中,拥有最多批准者的答案是错误的。

1、DOMContentLoaded事件直到CSS和JavaScript被执行并且DOM被解析(文档已加载)才会触发。

2、window.onload事件直到所有网络资源(如CSS和JavaScript)都被加载并且DOM被解析(文档已加载)才会触发。


基于 Chrome 80+ 的测试结果:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>DOMContentLoaded , load</title>
  
  <link href="http://localhost/public/css?sleep=5000" rel="stylesheet">
  <!-- 5000 milliseconds after the URL request the server begins to respond -->
</head>
<body>
  <img src="http://localhost/public/img?sleep=8000">
  <!-- 8000 milliseconds after the URL request the server starts responding to the resource -->
  
  <script>
    document.addEventListener('DOMContentLoaded', () => {
      console.log('DOMContentLoaded OKOK')
    })

    window.addEventListener('load', () => {
      console.log('window load OK')
    })
  </script>

  <script src="http://localhost/public/js?sleep=2000"></script>
  <!-- 2000 milliseconds after the URL request the server begins to respond -->
</body>
</html>

测试执行结果: 页面运行5秒后,执行console.log('domContentLoaded OKOK' 8秒时开始运行console.log('Window Load OK'

这不是正确的。DOMContentLoaded事件在HTML文档(仅限HTML文档,不包括样式表)解析完成后触发。 - adripanico
在发表评论前,请请求一项测试。 - GaoWuJie

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