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 相关文章推荐
jquery 问答知识整理
Feb 11 Javascript
用js将内容复制到剪贴板兼容浏览器
Mar 18 Javascript
javascript实现捕捉键盘上按下的键
May 05 Javascript
通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端的方法
Oct 01 Javascript
clipboard.js无需Flash无需依赖任何JS库实现文本复制与剪切
Oct 10 Javascript
完美实现八种js焦点轮播图(上篇)
Jul 18 Javascript
浅谈JavaScript中promise的使用
Jan 11 Javascript
easyui datebox 时间限制,datebox开始时间限制结束时间,datebox截止日期比起始日期大的实现代码
Jan 12 Javascript
Angular实现一个简单的多选复选框的弹出框指令实例
Apr 25 Javascript
详解vue.js数据传递以及数据分发slot
Jan 20 Javascript
JQuery元素快速查找与操作
Apr 22 jQuery
js中怎么判断两个字符串相等的实例
Jan 17 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
浅谈php正则表达式中的非贪婪模式匹配的使用
2014/11/25 PHP
thinkPHP5.0框架验证码调用及点击图片刷新简单实现方法
2018/09/07 PHP
ASP中进行HTML数据及JS数据编码函数
2009/11/11 Javascript
javascript之Partial Application学习
2013/01/10 Javascript
input输入框的自动匹配(原生代码)
2013/03/19 Javascript
zTree插件下拉树使用入门教程
2016/04/11 Javascript
一个字符串中出现次数最多的字符 统计这个次数【实现代码】
2016/04/29 Javascript
去除字符串左右两边的空格(实现代码)
2016/05/12 Javascript
网站发布后Bootstrap框架引用woff字体无法正常显示的解决方法
2016/11/24 Javascript
JavaScript定时器实现的原理分析
2016/12/06 Javascript
Angular.js初始化之ng-app的自动绑定与手动绑定详解
2017/07/31 Javascript
JS实现的3des+base64加密解密算法完整示例
2018/05/18 Javascript
vue-router权限控制(简单方式)
2018/10/29 Javascript
jQuery Datatables 动态列+跨列合并实现代码
2020/01/30 jQuery
vue 监听窗口变化对页面部分元素重新渲染操作
2020/07/28 Javascript
vue 路由meta 设置导航隐藏与显示功能的示例代码
2020/09/04 Javascript
Python中非常实用的一些功能和函数分享
2015/02/14 Python
彻底搞懂Python字符编码
2018/01/23 Python
Flask框架配置与调试操作示例
2018/07/23 Python
Python图像处理之简单画板实现方法示例
2018/08/30 Python
python连接mongodb密码认证实例
2018/10/16 Python
python算法与数据结构之冒泡排序实例详解
2019/06/22 Python
python字符串查找函数的用法详解
2019/07/08 Python
Python3 A*寻路算法实现方式
2019/12/24 Python
python numpy矩阵信息说明,shape,size,dtype
2020/05/22 Python
Python如何使用27行代码绘制星星图
2020/07/20 Python
CSS3实现多样的边框效果
2018/05/04 HTML / CSS
CSS实现聊天气泡效果
2020/04/26 HTML / CSS
英国领先的在线礼品店:Getting Personal
2019/09/24 全球购物
澳大利亚在线划船、露营和钓鱼商店:BCF Australia
2020/03/22 全球购物
自主招生自荐书
2013/11/29 职场文书
集体生日活动方案
2014/08/18 职场文书
2015年创先争优活动总结
2015/03/27 职场文书
被告代理词范文
2015/05/25 职场文书
摩登时代观后感
2015/06/03 职场文书
使用ICOM IC-R9500接收机同时测评十台收音机中波接收性能
2022/05/10 无线电