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 相关文章推荐
让回调函数 showResponse 也带上参数的代码
Aug 13 Javascript
简明json介绍
Sep 28 Javascript
跨浏览器开发经验总结(三)   警惕“IE依赖综合症”
May 13 Javascript
{}与function(){}选用空对象{}来存放keyValue
May 23 Javascript
使用GruntJS链接与压缩多个JavaScript文件过程详解
Aug 02 Javascript
Javascript玩转继承(二)
May 08 Javascript
30个经典的jQuery代码开发技巧
Dec 15 Javascript
javascript中offset、client、scroll的属性总结
Aug 13 Javascript
基于JS判断iframe是否加载成功的方法(多种浏览器)
May 13 Javascript
JS+html5 canvas实现的简单绘制折线图效果示例
Mar 13 Javascript
剖析Angular Component的源码示例
Mar 23 Javascript
JavaScript设计模式之单例模式简单实例教程
Jul 02 Javascript
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
是否存在第一台收音机的说法
2021/03/01 无线电
php函数的常用方法及注意之处小结
2011/07/10 PHP
基于Zend的Captcha机制的应用
2013/05/02 PHP
PHP实现股票趋势图和柱形图
2015/02/07 PHP
详解php的socket通信
2015/08/11 PHP
php实现将数组或对象写入到文件的方法小结【三种方法】
2020/04/22 PHP
基于jquery的finkyUI插件与Ajax实现页面数据加载功能
2010/12/03 Javascript
javascript innerHTML使用分析
2010/12/03 Javascript
利用jquery的获取JS文件中的字符串内容
2012/02/14 Javascript
用JQuery在网页中实现分隔条功能的代码
2012/08/09 Javascript
JavaScript中Cookie操作实例
2015/01/09 Javascript
javascript实现了照片拖拽点击置顶的照片墙代码
2015/04/03 Javascript
jQuery实现表格行上移下移和置顶的方法
2015/05/22 Javascript
解决angular的$http.post()提交数据时后台接收不到参数值问题的方法
2015/12/10 Javascript
js老生常谈之this,constructor ,prototype全面解析
2016/04/05 Javascript
AngularJS内建服务$location及其功能详解
2016/07/01 Javascript
jQuery ajax的功能实现方法详解
2017/01/06 Javascript
文本溢出插件jquery.dotdotdot.js使用方法详解
2017/06/22 jQuery
jQuery中的for循环var与let的区别
2018/04/21 jQuery
微信小程序开发常见问题及解决方案
2019/07/11 Javascript
iview form清除校验状态的实现
2019/09/19 Javascript
Vue 同步异步存值取值实现案例
2020/08/05 Javascript
[03:08]迎霜节狂欢!2018年迎霜节珍藏Ⅰ一览
2018/12/25 DOTA
python中的格式化输出用法总结
2016/07/28 Python
Request的中断和ErrorHandler实例解析
2018/02/12 Python
python itsdangerous模块的具体使用方法
2020/02/17 Python
python实现信号时域统计特征提取代码
2020/02/26 Python
Python telnet登陆功能实现代码
2020/04/16 Python
Python figure参数及subplot子图绘制代码
2020/04/18 Python
详解numpy1.19.4与python3.9版本冲突解决
2020/12/15 Python
电气专业推荐信范文
2013/11/18 职场文书
农民致富事迹材料
2014/01/23 职场文书
全国道德模范事迹
2014/02/01 职场文书
企业内部培训方案
2014/02/04 职场文书
2014年向国旗敬礼活动方案
2014/09/27 职场文书
如果用一句诗总结你的上半年,你会用哪句呢?
2019/07/16 职场文书