jquery ready函数源代码研究


Posted in Javascript onDecember 06, 2009

一般情况下都是设置body标签的onload监听window的load事件.但load事件是要在页面的元素全部加载完了才触发的,如果页面上图片较多或图片太大,就会导致初始化的代码未被执行的时候用户就做了其它操作了. Jquery库提供了一个非常方便好用的函数( $(selector).ready()),让我们可以在页面的dom加载完后就可以做相应的操作(当然,这还得看用户浏览器的支持).,而不用等待全部元素加载完成.例如:
$(document).ready(function (){ alert('use in page script tag') });
$(document).ready(function (){ alert('use in import js file') });
现在让我们来研究一下这个函数的实现.
原理:
在jquery脚本加载的时候,会设置一个isReady的标记,监听DOMContentLoaded事件(这个不是什么浏览器都有的,不同浏览器,jquery运作方式不一样).当然遇到调用ready函数的时候,如果isReady未被设置,那就是说页面未加载完,就会把要执行的函数用一个数组缓存起来,当页面加载完后,再把缓存的函数一一执行.
Jquery中的详细代码分析:

ready: function(fn) { 
        // 绑定监听器 
        bindReady(); 
        // 如果 DOM 加载完成 
        if ( jQuery.isReady ) 
            // 马上运行此函数 
            fn.call( document, jQuery ); 
        // 否则保存起来 
        else 
            // 把函数加入缓存数组中 
            jQuery.readyList.push( function() { return fn.call(this, jQuery); } ); 
        return this; 
}

让我们看看jquery如果实现不同浏览器dom加载完成的通知 bindReady()函数:

var readyBound = false; 
function bindReady(){ 
    if ( readyBound ) return; 
    readyBound = true; // Mozilla,opera,webkitnightlies支持DOMContentLoaded事件 
    if ( document.addEventListener && !jQuery.browser.opera) 
        // 直接使用事件回调即可 
        document.addEventListener( "DOMContentLoaded", jQuery.ready, false ); 
    // 如果是ie并且不是嵌在frame中 
    // 就需要不断地检查文档是否加载完 
    if ( jQuery.browser.msie && window == top ) (function(){ 
        if (jQuery.isReady) return; 
        try { 
            // 这个地方标记一下,在后面解析(1) 
            document.documentElement.doScroll("left"); 
        } catch( error ) { 
//// 这个地方标记一下,在后面解析(2) 
            setTimeout( arguments.callee, 0 ); 
            return; 
        } 
        // and execute any waiting functions 
        jQuery.ready(); 
    })(); 
    if ( jQuery.browser.opera ) 
        document.addEventListener( "DOMContentLoaded", function () { 
            if (jQuery.isReady) return; 
            for (var i = 0; i < document.styleSheets.length; i++) // 标记(3) 
                if (document.styleSheets[i].disabled) { 
                    setTimeout( arguments.callee, 0 ); 
                    return; 
                } 
            // and execute any waiting functions 
            jQuery.ready(); 
        }, false); 
    if ( jQuery.browser.safari ) { 
        var numStyles; 
        (function(){ 
            if (jQuery.isReady) return; 
            if ( document.readyState != "loaded" && document.readyState != "complete" ) { // 标记(4) 
                setTimeout( arguments.callee, 0 ); 
                return; 
            } 
            if ( numStyles === undefined ) 
                numStyles = jQuery("style, link[rel=stylesheet]").length; 
            if ( document.styleSheets.length != numStyles ) { // 标记(5) 
                setTimeout( arguments.callee, 0 ); 
                return; 
            } 
            // and execute any waiting functions 
            jQuery.ready(); 
        })(); 
    } 
    // A fallback to window.onload, that will always work 
    jQuery.event.add( window, "load", jQuery.ready ); // 标记(6) 
} 
}

(1):这个主要是测出ie下的dom ready,原理在这里http://javascript.nwbox.com/IEContentLoaded/,利用在ie下.当dom未完成解析时,调用document的document.documentElement.doScroll(”left”)会出错这个小技巧便可得知dom有没有ready了.
(2):setTimeout( arguments.callee, 0 )这句是表示延迟0秒调用,实际上它不会马上就调用,而是会尽可能快地调用,它告诉浏览器为当前任何挂起的事件运行完事件句柄并且完成了文档当前状态的更新后才调用. Arguments.callee即是外层的匿名函数,参数的调用者
(3):这个地方你也许觉得奇怪,为什么不在mozilla那里一起处理呢? 原因就是opera的DOMContentLoaded事件发生后,其css样式是还没完全可用的,所以要特殊处理,就是判断每个css的tag都是不是enable了.
(4),(5):safari中document.readyState的状态为loaded或complete时,css文件引入还未能确定是不是解析完了的,所以要通过判断其css文件数目
(6):最后,如果上面的hack都不支持的话…就用最保险的load事件,保证能执行到初始化代码.

Javascript 相关文章推荐
javascript 内存回收机制理解
Jan 17 Javascript
jQuery的初始化与对象构建之浅析
Apr 12 Javascript
探讨JavaScript中声明全局变量三种方式的异同
Dec 03 Javascript
轻松实现javascript图片轮播特效
Jan 13 Javascript
浅析JavaScript 箭头函数 generator Date JSON
May 23 Javascript
jQuery获取单击节点对象的方法
Jun 02 Javascript
关于原生js中bind函数的简单实现
Aug 10 Javascript
微信扫码支付零云插件版实例详解
Apr 26 Javascript
JavaScript严格模式下关于this的几种指向详解
Jul 12 Javascript
JS获取指定月份的天数两种实现方法
Jun 22 Javascript
微信开发之微信jssdk录音功能开发示例
Oct 22 Javascript
vue中div禁止点击事件的实现
Apr 02 Vue.js
javascript 模拟JQuery的Ready方法实现并出现的问题
Dec 06 #Javascript
javascript 动态生成私有变量访问器
Dec 06 #Javascript
JavaScript 加号(+)运算符号
Dec 06 #Javascript
javascript Demo模态窗口
Dec 06 #Javascript
jquery select操作的日期联动实现代码
Dec 06 #Javascript
JSON 编辑器实现代码
Dec 06 #Javascript
JS 控制非法字符的输入代码
Dec 04 #Javascript
You might like
PHP字符串函数系列之nl2br(),在字符串中的每个新行 (\n) 之前插入 HTML 换行符br
2011/11/10 PHP
浅析linux下apache服务器的配置和管理
2013/08/10 PHP
PHP图片处理之使用imagecopyresampled函数实现图片缩放例子
2014/11/19 PHP
老生常谈PHP 文件写入和读取(必看篇)
2017/05/22 PHP
jscript之List Excel Color Values
2007/06/13 Javascript
输入自动提示搜索提示功能的javascript:sugggestion.js
2013/09/02 Javascript
JQuery 给元素绑定click事件多次执行的解决方法
2014/09/09 Javascript
jQuery formValidator表单验证
2016/01/07 Javascript
又一款js时钟!transform实现时钟效果
2016/08/15 Javascript
[原创]SyntaxHighlighter自动识别并加载脚本语言
2017/02/07 Javascript
图文详解Javascript中的上下文和作用域
2017/02/15 Javascript
JS监控关闭浏览器操作的实例详解
2017/09/12 Javascript
webpack多页面开发实践
2017/12/18 Javascript
element-ui组件table实现自定义筛选功能的示例代码
2019/03/15 Javascript
五分钟搞懂Vuex实用知识(小结)
2019/08/12 Javascript
IE11下CKEditor在Bootstrap Modal中下拉问题的解决
2019/09/25 Javascript
VsCode里的Vue模板的实现
2020/08/12 Javascript
[52:57]2014 DOTA2国际邀请赛中国区预选赛 LGD-CDEC VS HGT
2014/05/21 DOTA
[39:07]LGD vs VP 2018国际邀请赛淘汰赛BO3 第二场 8.21
2018/08/22 DOTA
Python的Flask框架中实现简单的登录功能的教程
2015/04/20 Python
Python的Flask框架中实现登录用户的个人资料和头像的教程
2015/04/20 Python
使用Flask-Cache缓存实现给Flask提速的方法详解
2019/06/11 Python
Python调用Windows命令打印文件
2020/02/07 Python
TensorFlow获取加载模型中的全部张量名称代码
2020/02/11 Python
python os模块在系统管理中的应用
2020/06/22 Python
如何用PyPy让你的Python代码运行得更快
2020/12/02 Python
Ray-Ban雷朋奥地利官网:全球领先的太阳眼镜品牌
2020/10/12 全球购物
行政助理岗位职责范文
2013/12/03 职场文书
慰问敬老院活动总结
2014/04/26 职场文书
投标服务承诺书
2014/05/28 职场文书
奉献家乡演讲稿
2014/09/16 职场文书
导游词400字
2015/02/13 职场文书
爱国影片观后感
2015/06/18 职场文书
小学班级口号大全
2015/12/25 职场文书
Python 的 sum() Pythonic 的求和方法详细
2021/10/16 Python
Mysql 一主多从的部署
2022/05/20 MySQL