美文网首页
页面生命周期——DOMContentLoaded&Loa

页面生命周期——DOMContentLoaded&Loa

作者: 居客侠 | 来源:发表于2017-10-16 18:44 被阅读136次

页面生命周期内,有两个非常重要的事件:
1.DOMContentLoaded
此时浏览器已经完全加载了HTML文件,并且DOM树已经生成好了。但是其他外部资源,如样式文件、图片、字体等并没有加载好
2.Load
此时浏览器已经将所有的资源都加载完毕,可以正确读取页面中的资源。

两个事件标识了两种不同的时刻:
1.DOMContentLoaded
DOM已经完成加载,此时可以为这些DOM元素绑定事件,初始化接口等
2.Load
其他外部资源均已加载完成,可以正确读出这些资源的信息,如图片的宽高等

DOMContentLoaded

使用addEventListener监听该事件:

document.addEventListener('DOMContentLoaded', ready)

举一个🌰

<script>
  function ready() {
    alert('DOM is ready');
    
    var img = document.getElementById('img')
    // 由于图片属于外部资源,尚未下载完成,因此暂无法读到数据,所以结果是0x0
    alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
  }

  document.addEventListener("DOMContentLoaded", ready);
</script>

![](https://img.haomeiwen.com/i280956/d030e8153b43d7be.gif?imageMogr2/auto-orient/strip)

虽然DOMContentLoaded如我们期望的那样工作,但仍在个别情况下有所不同

异步scripts

当解析器(HTML Paser)读取到<script>...</script>内联标签时,会阻塞DOM构建,它会立即执行脚本,原因是可能这些脚本会影响DOM,因此需要等到这些脚本都执行完成了,才会触发DOMContentLoaded事件。
外部脚本(<script src="...">...</script>)也是如此,浏览器需要等到加载后再执行完成才可以继续执行。

是否可以让外部引用的脚本延后执行,答案是可以的。asyncdefer属性可以让外部脚本延后执行,而不阻塞浏览器解析文档。asyncdefer仅在<script src="...">...</script>情形下起作用,对内联脚本是无效的。用户可以在脚本完成加载前,就可以看到页面了,提升了用户体验。

async & defer

这两个属性都是告诉浏览器,标记的脚本不需要等待它加载完成,浏览器可以继续完成DOM构建和渲染
两者的区别如下:

async defer
执行顺序 谁先完成下载谁先执行 执行顺序始终遵循加载的顺序,即使先下载完成了
DOMContentLoaded 如果页面加载时间较长,脚本可能会先执行;绝大多数会在DOMContentLoaded之后执行,但一定是在Load事件之前执行 脚本会在DOMContentLoaded之前执行,但不阻塞浏览器加载和解析文档,即defer脚本与浏览器加载顺序无关先后

因此async更符合一些应用场景。

Timeline

样式阻塞

对于外部样式文件而言,并不会影响到DOMCotentLoaded事件,它并不会等待外部样式文件加载完成。
但是!!!,如果一个脚本是紧跟着link样式出现,那么这个脚本就会等样式加载完成了。如下:

<link type="text/css" rel="stylesheet" href="style.css">
<script>
  // the script doesn't not execute until the stylesheet is loaded
  alert(getComputedStyle(document.body).marginTop);
</script>

原因是浏览器猜测脚本可能会读取一些样式信息,如位置、颜色,显然脚本就需要等到样式的加载完成了。

这也是为什么我们最好把脚本文件放到HTML文档的最后再加载,而不要把脚本放在head标签里,除非你清楚放在head标签里是必要的。

浏览器表单自动填充

这个是顺便引出的话题,你知道浏览器内置的表单自动填充在什么时候完成么?没错,就是DOMContentLoaded触发的时候

window.onload

当所有外部资源都完成加载后,浏览器触发load事件,此时可以读取外部资源信息了

<script>
  window.onload = function() {
    alert('Page loaded');

    // image is loaded at this time
    alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
  };
</script>

![](https://img.haomeiwen.com/i280956/d030e8153b43d7be.gif?imageMogr2/auto-orient/strip)

Chrome DevTool中的load

image.png

我们通常可以通过DOMContentLoaded的时间去衡量一个页面加载的速度,因为此时用户已经可以看到这个页面,并可以有一些交互了。

兼容性

以上提到的使用document.addEventListener监听DOMCotentLoaded事件,在IE9+都是有效的。需要兼容IE低版本

// 摘抄自jQuery源码
if ( document.readyState === "complete" ||
    ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
    // Handle it asynchronously to allow scripts the opportunity to delay ready
    window.setTimeout( jQuery.ready );
}

比较粗暴,反复去嗅探是否可以执行ready函数。有兴趣去读读jQuery源码,很有意思

扩展阅读

DOMContentLoaded
onload
page lifecycle

相关文章

网友评论

      本文标题:页面生命周期——DOMContentLoaded&Loa

      本文链接:https://www.haomeiwen.com/subject/qxakuxtx.html