domReady机制探究及DOMContentLoaded研究
2016-11-10 20:16
88 查看
domReady机制是很多框架和库都具有的种子模块,使用了在DOM树解析完成后就立即响应,不用等待图片等资源下载完成(onload执行时候表示这些资源完全下载完成)的一种机制,那怎么实现呢。
1)支持DOMContentLoaded事件的,就使用DOMContentLoaded事件;
2)不支持的,就用来自Diego Perini发现的著名Hack兼容。兼容原理大概就是,通过IE中的document.documentElement.doScroll(‘left’)来判断DOM树是否创建完毕或者使用监控script标签的onreadystatechange得到它的readyState属性判断【遗憾的是经过我们的实验,在IE下domReady机制总会在onload后执行】
deferjs.js
demo1.js
readyState 属性返回当前文档的状态(载入中……)。
该属性返回以下值:
uninitialized - 还未开始载入
loading - 载入中
interactive - 已加载,文档与用户可以开始交互并引发DOMContentLoaded事件
complete - 载入完成
IE的 script的readyState
FireFox的script 元素不支持onreadystatechange事件,只支持onload事件
IE的 script 元素支持onreadystatechange事件,不支持onload事件
只针对IE readyState 的值 可能为 以下几个 :
“uninitialized” – 原始状态
“loading” – 下载数据中..
“loaded” – 下载完成
“interactive” – 还未执行完毕.
“complete” – 脚本执行完毕
defer和onload函数
defer 属性仅适用于外部脚本(只有在使用 src 属性时)
* 如果 async=”async”:脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)
* 如果不使用 async 且 defer=”defer”:脚本将在页面完成解析时执行
* 如果既不使用 async 也不使用 defer:在浏览器继续解析页面之前,立即读取并执行脚本
dom.fireReady函数在onload函数之后执行
在更早的IE版本中,可以通过每隔一段时间执行一次
demo1.html中将script标签放入到
在chrome中的顺序是:
jquery的ready函数外 (打印结果:在js中)
带defer的script (打印结果:defer script)
jquery的ready函数里面 (打印结果:jquery中的ready函数)
监听DOMContentLoaded要执行的函数 dom.fireReady(打印结果:DOMContentLoaded和我是domReady系列)
onload函数(打印结果:onload函数)
带defer的script标签,IE8以下中不支持defer属性
dom.fireReady在IE中的逻辑是在
综上所诉,执行的顺序应该为:
jquery的ready函数外
【非IE下】
带defer的script
jquery的ready函数里面
触发
【IE常用来判断DOM树是否解析完成】document.documentElement.doScroll 这时可以让HTML元素使用doScroll方法,抛出错误就是DOM树未解析完成
onload函数(打印结果:onload函数)【图片flash等资源都加载完毕】
最后附上监测IE,在IE的onload函数后面执行执行的另外一种实现方式
参考阅读:
- 司徒正美 - 《javascript框架设计》
- 司徒正美-javascript的事件加载
- 主流JS框架中DOMReady事件的实现
- javascript的domReady
- document.readyState的属性
- DOMContentLoaded介绍
- 又说 动态加载 script. ie 下 script Element 的 readyState状态
1)支持DOMContentLoaded事件的,就使用DOMContentLoaded事件;
2)不支持的,就用来自Diego Perini发现的著名Hack兼容。兼容原理大概就是,通过IE中的document.documentElement.doScroll(‘left’)来判断DOM树是否创建完毕或者使用监控script标签的onreadystatechange得到它的readyState属性判断【遗憾的是经过我们的实验,在IE下domReady机制总会在onload后执行】
1. domReady机制在IE7-8下
1.1 domReady机制源码(包括IE/非IE)
demo1.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> DOMContentLoaded Demo</title> </head> <body> <div id="div1"></div> <script defer='defer' src="deferjs.js"></script> <script src="http://cdn.bootcss.com/jquery/1.12.4/jquery.js"></script> <script type="text/javascript" src="demo1.js"></script> <script> dom.Ready(function() { console.info("我的domReady1"); }); </script> </body> </html>
deferjs.js
console.log("defer script");
demo1.js
dom = []; dom.isReady = false; dom.isFunction = function(obj) { return Object.prototype.toString.call(obj) === "[object Function]"; }; dom.Ready = function(fn) { dom.initReady(); //如果没有建成DOM树,则走第二步,存储起来一起杀 if (dom.isFunction(fn)) { if (dom.isReady) { fn(); //如果已经建成DOM,则来一个杀一个 } else { dom.push(fn); //存储加载事件 } } }; dom.fireReady = function() { if (dom.isReady) return; dom.isReady = true; for (var i = 0, n = dom.length; i < n; i++) { var fn = dom[i]; fn(); } dom.length = 0; //清空事件 }; dom.initReady = function() { if (document.addEventListener) {//非IE document.addEventListener("DOMContentLoaded", function() { console.log("DOMContentLoaded"); document.removeEventListener("DOMContentLoaded", arguments.callee, false); //清除加载函数 dom.fireReady(); }, false); } else {//IE走这条线 if (document.getElementById) { document.write("<script id=\"ie-domReady\" defer='defer'src=\"//:\"><\/script>"); document.getElementById("ie-domReady").onreadystatechange = function() { console.log(this.readyState); if (this.readyState === "complete") { //只针对IE readyState 的值 complete--脚本执行完成。 //这个时候DOM树肯定已经解析完成了,不支持defer属性 //会在onload函数之后执行。 dom.fireReady(); console.log('this.readyState === "complete"'); this.onreadystatechange = null; this.parentNode.removeChild(this); } }; } } }; /**********测试**************************************************/ dom.Ready(function() { console.info("我的domReady2"); }); /*$(document).ready(function() { dom.Ready(function() { console.info("我的domReady4在jquery的ready函数中"); }); console.log('jquery中的ready函数'); });*/ dom.Ready(function() { console.info("我的domReady3"); }); console.log('在js中'); window.onload = function(){ console.log("onload函数"); };
1.2 背景知识介绍
document.readystate
readyState 属性返回当前文档的状态(载入中……)。
该属性返回以下值:
uninitialized - 还未开始载入
loading - 载入中
interactive - 已加载,文档与用户可以开始交互并引发DOMContentLoaded事件
complete - 载入完成
IE的 script的readyState
FireFox的script 元素不支持onreadystatechange事件,只支持onload事件
IE的 script 元素支持onreadystatechange事件,不支持onload事件
只针对IE readyState 的值 可能为 以下几个 :
“uninitialized” – 原始状态
“loading” – 下载数据中..
“loaded” – 下载完成
“interactive” – 还未执行完毕.
“complete” – 脚本执行完毕
defer和onload函数
<script defer='defer' src="deferjs.js"></script>
defer 属性仅适用于外部脚本(只有在使用 src 属性时)
* 如果 async=”async”:脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)
* 如果不使用 async 且 defer=”defer”:脚本将在页面完成解析时执行
* 如果既不使用 async 也不使用 defer:在浏览器继续解析页面之前,立即读取并执行脚本
1.3 结果分析
在IE7/8打印的结果是:dom.fireReady函数在onload函数之后执行
1.4 IE下监控DOM树是否解析完成的其他做法
除了使用document.write("<script id=\"ie-domReady\" defer='defer'src=\"//:\"><\/script>")还可以监控DOM树是否解析完成
在更早的IE版本中,可以通过每隔一段时间执行一次
document.documentElement.doScroll("left")来检测这一状态,因为这条代码在DOM加载完毕之前执行时会抛出错误(throw an error)
(function() { try { //在DOM未建完之前调用元素的doScroll抛出错误 document.documentElement.doScroll('left'); } catch (e) { //延迟再试 setTimeout(arguments.callee, 50); return; } init(); //没有错误则执行用户回调 })();
2. domReady机制在chrome中
将上面的demo2.js文件下注释的jquery的ready函数取消注释进行执行,得到结果是:demo1.html中将script标签放入到
<head>得到的结果是一样的。
在chrome中的顺序是:
document.readyState为
loading
jquery的ready函数外 (打印结果:在js中)
document.readyState为
interactive【DOM解析完成】
带defer的script (打印结果:defer script)
jquery的ready函数里面 (打印结果:jquery中的ready函数)
监听DOMContentLoaded要执行的函数 dom.fireReady(打印结果:DOMContentLoaded和我是domReady系列)
document.readyState为
compelete
onload函数(打印结果:onload函数)
3.总结
1,2区别:带defer的script标签,IE8以下中不支持defer属性
dom.fireReady在IE中的逻辑是在
document.readyState=="compelte"后,会在onload函数之后紧接着执行,在chrome/Firfox的逻辑是在
document.addEventListener("DOMContentLoaded",function(){})的回掉函数中。
综上所诉,执行的顺序应该为:
document.readyState为
loading
jquery的ready函数外
【非IE下】
document.readyState为
interactive【DOM解析完成】
带defer的script
jquery的ready函数里面
触发
DOMContentLoaded事件,监听DOMContentLoaded要执行的函数
【IE常用来判断DOM树是否解析完成】document.documentElement.doScroll 这时可以让HTML元素使用doScroll方法,抛出错误就是DOM树未解析完成
document.readyState为
compelete
onload函数(打印结果:onload函数)【图片flash等资源都加载完毕】
最后附上监测IE,在IE的onload函数后面执行执行的另外一种实现方式
//http://javascript.nwbox.com/IEContentLoaded/ //by Diego Perini 2007.10.5 function IEContentLoaded(w, fn) { var d = w.document||document, done = false, init = function() { if (!done) { //只执行一次 done = true; fn(); } }; (function() { try { //在DOM未建完之前调用元素的doScroll抛出错误 d.documentElement.doScroll('left'); } catch (e) { //延迟再试 setTimeout(arguments.callee, 50); return; } init(); //没有错误则执行用户回调 })(); // 如果用户是在domReady之后绑定这个函数呢?立即执行它 d.onreadystatechange = function() { if (d.readyState == 'complete') { d.onreadystatechange = null; init(); } }; }
参考阅读:
- 司徒正美 - 《javascript框架设计》
- 司徒正美-javascript的事件加载
- 主流JS框架中DOMReady事件的实现
- javascript的domReady
- document.readyState的属性
- DOMContentLoaded介绍
- 又说 动态加载 script. ie 下 script Element 的 readyState状态
相关文章推荐
- 探究PHP底层运行机制
- Android深入探究笔记之一 -- 我的第一个 Android 程序,基于 Intent 的组件交互机制
- Android中图片加载框架Glide解析3----深入探究Glide的缓存机制
- 点击TextView透传原因剖析--Android事件传递机制探究
- Java虚拟机探究之--垃圾回收机制
- 一点一滴探究JVM之类加载机制
- Android 开发艺术探究V第三章之view的事件分发机制
- Linux Cache 机制探究
- Openwrt ubus机制的探究
- iOS-视图,动画渲染机制探究
- Jedis Pipeline机制简单探究
- java 反射机制探究
- Android图片加载框架最全解析(三),深入探究Glide的缓存机制
- 再次探究Android ListView缓存机制
- 探究Handler+Message机制的原理
- Android消息机制浅析——原理探究
- Azkaban的Web Server源码探究系列6: alerters及插件机制分析
- Java中Iterator(迭代器)的用法及其背后机制的探究
- Java中Iterator(迭代器)的用法及其背后机制的探究
- View事件分发机制探究