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 相关文章推荐
ExtJS 简介 让你知道extjs是什么
Dec 29 Javascript
使用JQUERY Tabs插件宿主IFRAMES
Jan 01 Javascript
jquery中获取select选中值的代码
Jun 27 Javascript
js中文逗号转英文实现
Feb 11 Javascript
js replace替换所有匹配的字符串
Feb 13 Javascript
详细解密jsonp跨域请求
Apr 15 Javascript
jQuery解析json格式数据简单实例
Jan 22 Javascript
Angular2-primeNG文件上传模块FileUpload使用详解
Jan 14 Javascript
无循环 JavaScript(map、reduce、filter和find)
Apr 08 Javascript
细说Vue组件的服务器端渲染的过程
May 30 Javascript
移动端 Vue+Vant 的Uploader 实现上传、压缩、旋转图片功能
Jun 10 Javascript
Vue实现简单计算器
Jan 20 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
将兴奋、喜悦和坎加斯带到戴安娜:亚马逊公主
2020/03/03 欧美动漫
PHPCMS的使用小结
2010/09/20 PHP
ThinkPHP基本的增删查改操作实例教程
2014/08/22 PHP
CodeIgniter多语言实现方法详解
2016/01/20 PHP
获取JavaScript用户自定义类的类名称的代码
2007/03/08 Javascript
cnblogs csdn 代码运行框实现代码
2009/11/02 Javascript
原生JS实现首页进度加载动画
2016/09/14 Javascript
input框中的name和id的区别
2016/11/16 Javascript
分类解析jQuery选择器
2016/11/23 Javascript
layer弹出层中H5播放器全屏出错的解决方法
2017/02/21 Javascript
JS实现汉字与Unicode码相互转换的方法详解
2017/04/28 Javascript
vue2项目使用sass的示例代码
2017/06/28 Javascript
JS实现点击循环切换显示内容的方法
2017/10/19 Javascript
JS中数组与对象的遍历方法实例小结
2018/08/14 Javascript
基于JavaScript实现一个简单的Vue
2018/09/26 Javascript
全面解析js中的原型,原型对象,原型链
2021/01/25 Javascript
[56:41]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 Newbee vs OG
2018/04/01 DOTA
python网络编程之数据传输UDP实例分析
2015/05/20 Python
pytorch 转换矩阵的维数位置方法
2018/12/08 Python
对python实现合并两个排序链表的方法详解
2019/01/23 Python
在PyTorch中Tensor的查找和筛选例子
2019/08/18 Python
python  logging日志打印过程解析
2019/10/22 Python
Python字符串的修改方法实例
2019/12/19 Python
python统计字符串中字母出现次数代码实例
2020/03/02 Python
美国面料纺织品商城:Fabric.com
2017/06/28 全球购物
美国花园雕像和家居装饰网上商店:Design Toscano
2019/03/09 全球购物
惠普香港官方商店:HP香港
2019/04/30 全球购物
Opodo意大利:欧洲市场上领先的在线旅行社
2019/10/24 全球购物
校园报刊亭的创业计划书
2014/01/02 职场文书
工商治理实习生的自我评价分享
2014/02/20 职场文书
高中军训感言500字
2014/02/24 职场文书
协议书的格式
2014/04/23 职场文书
派出所所长先进事迹
2014/05/19 职场文书
报考公务员诚信承诺书
2014/08/29 职场文书
对照四风自我剖析材料
2014/10/07 职场文书
元旦晚会开场白
2015/05/29 职场文书