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 组件之旅(四):测试 JavaScript 组件
Oct 28 Javascript
jQuery方法简洁实现隔行换色及toggleClass的使用
Mar 15 Javascript
解析使用JS 清空File控件的路径值
Jul 08 Javascript
基于jquery自定义的漂亮单选按钮RadioButton
Nov 19 Javascript
Jquery中的层次选择器与find()的区别示例介绍
Feb 20 Javascript
JS获取当前日期时间并定时刷新示例
Mar 04 Javascript
JQuery Mobile实现导航栏和页脚
Mar 09 Javascript
jQuery基于json与cookie实现购物车的方法
Apr 15 Javascript
JQuery Ajax WebService传递参数的简单实例
Nov 02 Javascript
javascript实现fetch请求返回的统一拦截
Dec 22 Javascript
vue学习笔记之作用域插槽实例分析
Feb 01 Javascript
Javascript实现html转pdf高清版(提高分辨率)
Feb 19 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中的观察者模式
2010/03/24 PHP
php 伪造本地文件包含漏洞的代码
2011/11/03 PHP
比较详细PHP生成静态页面教程
2012/01/10 PHP
数据库中排序的对比及使用条件详解
2012/02/23 PHP
解析php中获取url与物理路径的总结
2013/06/21 PHP
CI框架中site_url()和base_url()的区别
2015/01/07 PHP
PHP数组实际占用内存大小原理解析
2020/12/11 PHP
js nextSibling属性和previousSibling属性概述及使用注意
2013/02/16 Javascript
jquery获取被勾选的checked(选中)的那一行的3列和4列的值
2013/07/04 Javascript
javascript检测两个数组是否相似
2015/05/19 Javascript
jQuery实现向下滑出的平滑下拉菜单效果
2015/08/21 Javascript
详解HTTPS 的原理和 NodeJS 的实现
2017/07/04 NodeJs
详解在vue-cli项目中使用mockjs(请求数据删除数据)
2017/10/23 Javascript
详解Vue路由自动注入实践
2019/04/17 Javascript
解决vue props传Array/Object类型值,子组件报错的情况
2020/11/07 Javascript
[55:26]DOTA2-DPC中国联赛 正赛 Aster vs LBZS BO3 第一场 2月23日
2021/03/11 DOTA
详解Python中open()函数指定文件打开方式的用法
2016/06/04 Python
python自定义函数实现一个数的三次方计算方法
2019/01/20 Python
基于 Django 的手机管理系统实现过程详解
2019/08/16 Python
Python数据分析模块pandas用法详解
2019/09/04 Python
python3.6连接mysql数据库及增删改查操作详解
2020/02/10 Python
Pycharm导入anaconda环境的教程图解
2020/07/31 Python
Python+OpenCV图像处理——打印图片属性、设置存储路径、调用摄像头
2020/10/22 Python
静态变量和实例变量的区别
2015/07/07 面试题
房地产管理毕业生自荐信
2013/11/04 职场文书
数学教育专业求职信
2014/07/22 职场文书
公司委托书怎么写
2014/08/02 职场文书
2014年军人思想汇报范文
2014/10/12 职场文书
2014年团队工作总结
2014/11/24 职场文书
销售员自我评价
2015/03/11 职场文书
妈妈再爱我一次观后感
2015/06/08 职场文书
2019个人工作总结
2019/06/21 职场文书
Python图片处理之图片裁剪教程
2021/05/27 Python
eval(cmd)与eval($cmd)的区别与联系
2021/07/07 PHP
python3操作redis实现List列表实例
2021/08/04 Python
Python实现批量自动整理文件
2022/03/16 Python