DOMContentLoaded、readystatechange、load、ready详谈

对前端同窗而言,loade,unload,DOMContentLoaded等页面加载过程当中会触发的事件确定是都接触过,不过要是具体问各个事件的区别,我就不是那么能清晰的解答上来的了。正好刚刚在无阻塞脚本那看到了DOMContentLoaded事件,就来翻翻具体文档详细看一下各个事件吧。常言道温故而知新,让咱们一块儿回头看一下javascript

触发时机

先看下各个事件的触发时机(参考自MDN)css

DOMContentLoaded

当初始html文档彻底加载并解析以后触发,无需等待样式、图片、子frame结束。做为明显的对比,load事件只有一个页面彻底被加载时才触发。改用DOMContentLoaded的地方经常是load来代替,这是错误的。 tips: 有许多通用和独立的库提供跨浏览器方法来检测 DOM 是否已准备就绪即ready事件,后面咱们能够看下zepto的实现html

load

当一个资源及其依赖的资源结束加载时触发。从这里能够看到须要等待依赖资源的结束加载。前端

readystatechange

document有readyState属性来描述document的loading状态,readyState的改变会触发readystatechange事件.html5

  • loadingjava

    文档仍然在加载jquery

  • interactiveapi

    文档结束加载而且被解析,可是想图片,样式,frame之类的子资源仍在加载浏览器

  • completedom

    文档和子资源已经结束加载,该状态代表将要触发load事件。

所以,咱们一样可使用该事件来判断dom的加载状态。
但并不是全部对象都会经历 readyState 的这几个阶段,有时候须要

beforeunload

当浏览器窗口,文档或其资源将要卸载时,会触发beforeunload事件。这个文档是依然可见的,而且这个事件在这一刻是能够取消的.
若是处理函数为Event对象的returnValue属性赋值非空字符串,浏览器会弹出一个对话框,来询问用户是否肯定要离开当前页面(以下示例)。有些浏览器会将返回的字符串展现在弹框里,但有些其余浏览器只展现它们自定义的信息。没有赋值时,该事件不作任何响应。 tip:2011年5月25号起,html5中指出,该事件中调用window.alert(), window.confirm(), and window.prompt()方法将会被忽略。

unload

当文档或者一个子资源将要被卸载时,在beforeunload 、pagehide两个事件以后触发。
文档会处于一个特定状态。

  • 全部资源仍存在 (图片, iframe 等.)
  • 对于终端用户全部资源均不可见
  • 界面交互无效 (window.open, alert, confirm 等.)
  • 错误不会中止卸载文档的过程

页面加载中的执行顺序

从上面的定义,咱们能够得出一个比较清晰的顺序了。

  1. 页面加载开始,首先确定是先发出加载资源的请求,加载未完成以前,不触发任何事件。

  2. document加载结束并解析,此时css等其余资源未加载完成。

    此时readyState为'interactive',代表document已经load并解析完成,触发 readystatechange,而后触发DOMContentLoaded(在大多数浏览器上的表现如此)。捎带提一句,此时,加载完成且带有defer标记的脚本,会按顺序开始执行。

  3. css、img等子资源加载完成以后

    此时触发window.load事件

  4. 点击关闭标签或者刷新时,会依次触发beforeunload、unload事件。

可能概念看的有点枯燥,仍是看下代码比较清晰。你们能够看下,下面的代码会依次输出什么。

<!DOCTYPE html>
<html>

<head>
    <title>文档加载事件</title>
    <script> document.addEventListener("DOMContentLoaded", function (event) { console.log("初始DOM 加载并解析"); }); window.addEventListener("load", function (event) { console.log("window 全部资源加载完成"); }); document.onreadystatechange = function () { console.log(document.readyState) if (document.readyState === "complete") { console.log('初始DOM,加载解析完成') } } window.addEventListener("beforeunload", function (event) { console.log('即将关闭') event.returnValue = "\o/"; }); window.addEventListener('unload', function (event) { console.log('即将关闭1'); }); </script>
    <link rel="stylesheet" href="./test.css">
</head>

<body>
    <div id="root">dom事件</div>
    <script src="./index.js"></script>
</body>

</html>
复制代码

依次输出以下:

interactive //(index):15
    初始DOM 加载并解析 //(index):8
    complet//(index):15 
    初始DOM,加载解析完成//(index):17 
    window 全部资源加载完成//(index):11 
    //点击关闭按钮
    即将关闭
    即将关闭2  
复制代码

关于ready

像jquery、zepto等类库中都有document一个ready方法,来确保咱们的操做在初始dom加载以后进行,原生dom定义里是没有这个api的,是大牛们封装了一下判断的过程,提供咱们以便利。
有了前面的例子,让咱们猜一下他们是怎么实现的。

  1. ready对应的状态是初始化dom已经加载完成,咱们来看一下什么状况下对应该状况。

    有下面几个状态,complete、interactive 还有一个DOMContentLoaded也是初始dom加载完成,固然还有load事件,显然这里不会用到它,相对其余状态而言有点太晚了。

  2. 肯定触发条件以后,下面的实现就简单了,判断就好了。

以zepto为例,咱们看下实现:

//声明变量,不仅使用interactive,是由于前面提到这些状态不必定所有出现
readyRE = /complete|loaded|interactive/

ready: function(callback){
      // need to check if document.body exists for IE as that browser reports
      // document ready when it hasn't yet created the body element
      if (readyRE.test(document.readyState) && document.body) callback($)
      else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
      return this
    } 
复制代码

至此,介绍就结束了。对我而言,明了原来不太清楚的概念,但愿对你们也有所帮助。

更新

评论区中有同窗提到DOMContentLoaded时机的问题,即css 没有加载完成,应该不会触发 DOMContentLoaded。
这个问题可能会存在,举个例子:

<div id="example-root">测试DOMContentLoaded 与css</div>
//随手拿了一段css
<link rel="stylesheet" href="https://m.jb51.net/skin/mobile2017/css/common.css">
<script> document.addEventListener('DOMContentLoaded', function () { alert('DOMContentLoaded 触发'); }); </script>
复制代码

此时能够看到触发时,确实是css已经加载完成。 可是先不要忙着下结论,代码换一下顺序:

<div id="example-root">测试DOMContentLoaded 与css</div>
<script> document.addEventListener('DOMContentLoaded', function () { alert('DOMContentLoaded 触发'); }); </script>
//随手拿了一段css
<link rel="stylesheet" href="https://m.jb51.net/skin/mobile2017/css/common.css">
复制代码

这时候能够看到,触发DOMContentLoaded时,css依旧处于pending状态 若是会等待css的完成,显然此时css应该加载完成了。

结论

DOMContentLoaded触发确实不会等待css加载完成的。上述现象的出现不是DOMContentLoaded时机的问题,是js执行顺序问题。 js监听事件的时候,css已经加载完成了,因此给人一种错觉。

相关文章
相关标签/搜索