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对ajax的支持介绍
Dec 10 Javascript
利用js正则表达式验证手机号,email地址,邮政编码
Jan 23 Javascript
简单谈谈JavaScript的同步与异步
Dec 31 Javascript
javascript html5实现表单验证
Mar 01 Javascript
jQuery查找节点并获取节点属性的方法
Sep 09 Javascript
微信小程序 使用picker封装省市区三级联动实例代码
Oct 28 Javascript
Angular4学习笔记之实现绑定和分包
Aug 01 Javascript
node.js 发布订阅模式的实例
Sep 10 Javascript
使用webpack-dev-server处理跨域请求的方法
Apr 18 Javascript
React 实现拖拽功能的示例代码
Jan 06 Javascript
原生JavaScript实现的无缝滚动功能详解
Jan 17 Javascript
微信小程序tab左右滑动切换功能的实现代码
Feb 08 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-redis中文文档介绍
2013/02/07 PHP
基于php的CMS中展示文章类实例分析
2015/06/18 PHP
Yii2针对指定url的生成及图片等的引入方法小结
2016/07/18 PHP
javascript 24小时弹出一次的代码(利用cookies)
2009/09/03 Javascript
jquery重复提交请求的原因浅析
2014/05/23 Javascript
JavaScript异步加载浅析
2014/12/28 Javascript
jquery实现树形菜单完整代码
2015/12/29 Javascript
JQuery 传送中文乱码问题的简单解决办法
2016/05/24 Javascript
微信js-sdk上传与下载图片接口用法示例
2016/10/12 Javascript
微信小程序 数据绑定详解及实例
2016/10/25 Javascript
JavaScript获取中英文混合字符串长度的方法示例
2017/02/04 Javascript
Vue组件tree实现树形菜单
2017/04/13 Javascript
zTree jQuery 树插件的使用(实例讲解)
2017/09/25 jQuery
Bootstrap table表格初始化表格数据的方法
2018/07/25 Javascript
js实现多个倒计时并行 js拼团倒计时
2019/02/25 Javascript
vue 使用axios 数据请求第三方插件的使用教程详解
2019/07/05 Javascript
在Django中编写模版节点及注册标签的方法
2015/07/20 Python
Python正则表达式教程之二:捕获篇
2017/03/02 Python
详解python之多进程和进程池(Processing库)
2017/06/09 Python
Python列表解析配合if else的方法
2018/06/23 Python
python中ASCII码字符与int之间的转换方法
2018/07/09 Python
python实现录音小程序
2020/10/26 Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
2018/10/30 Python
python3 爬取图片的实例代码
2018/11/06 Python
wxPython实现文本框基础组件
2019/11/18 Python
浅谈pytorch卷积核大小的设置对全连接神经元的影响
2020/01/10 Python
浅析pip安装第三方库及pycharm中导入第三方库的问题
2020/03/10 Python
python 如何把docker-compose.yaml导入到数据库相关条目里
2021/01/15 Python
阿玛尼化妆品美国官网:Giorgio Armani Beauty
2017/02/02 全球购物
Capitol Lighting的1800lighting.com:住宅和商业照明
2019/04/10 全球购物
Haggar官网:美国男装品牌
2020/02/16 全球购物
夜大毕业生自我评价分享
2013/11/10 职场文书
教师作风建设剖析材料
2014/10/11 职场文书
浅谈Python项目的服务器部署
2021/04/25 Python
Python常遇到的错误和异常
2021/11/02 Python
德劲DE1105机评
2022/04/05 无线电