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 相关文章推荐
IE8中使用javascript动态加载CSS的解决方法
Jun 17 Javascript
PHP中使用微秒计算脚本执行时间例子
Nov 19 Javascript
node.js中的http.response.removeHeader方法使用说明
Dec 14 Javascript
理解JavaScript的变量的入门教程
Jul 07 Javascript
jQuery模拟物体自由落体运动(附演示与demo源码下载)
Jan 21 Javascript
简单实现jQuery多选框功能
Jan 09 Javascript
Vue+axios 实现http拦截及路由拦截实例
Apr 25 Javascript
JS实现数组去重,显示重复元素及个数的方法示例
Jan 21 Javascript
微信域名检测接口调用演示步骤(含PHP、Python)
Dec 08 Javascript
js实现聊天对话框
Feb 08 Javascript
js实现带积分弹球小游戏
Jul 21 Javascript
Vue实现Header渐隐渐现效果的实例代码
Nov 05 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
用Zend Encode编写开发PHP程序
2006/10/09 PHP
PHPEXCEL 使用小记
2013/01/06 PHP
PHP实现邮件群发的源码
2013/06/18 PHP
Linux下PHP连接Oracle数据库
2014/08/20 PHP
PHP中常用的输出函数总结
2014/09/22 PHP
PHP中生成UUID自定义函数分享
2015/06/10 PHP
PHP观察者模式示例【Laravel框架中有用到】
2018/06/15 PHP
PHP命名空间namespace及use的简单用法分析
2018/08/03 PHP
JS操作XML中DTD介绍及使用方法分析
2019/07/04 PHP
一些常用弹出窗口/拖放/异步文件上传等实用代码
2013/01/06 Javascript
JavaScript表达式:URL 协议介绍
2013/03/10 Javascript
JS注册/移除事件处理程序(ExtJS应用程序设计实战)
2013/05/07 Javascript
js 判断文件类型并控制表单提交示例代码
2013/11/14 Javascript
JS Loading功能的简单实现
2013/11/29 Javascript
通过复制Table生成word和excel的javascript代码
2014/01/20 Javascript
javascript中hasOwnProperty() 方法使用指南
2015/03/09 Javascript
简述JavaScript对传统文档对象模型的支持
2015/06/16 Javascript
javascript下拉列表中显示树形菜单的实现方法
2015/11/17 Javascript
js 获取站点应用名的简单实例
2016/08/18 Javascript
vue.js移动端tab组件的封装实践实例
2017/06/30 Javascript
Vue.js划分组件的方法
2017/10/29 Javascript
如何运行Python程序的方法
2013/04/21 Python
python 自动化将markdown文件转成html文件的方法
2016/09/23 Python
Pandas DataFrame 取一行数据会得到Series的方法
2018/11/10 Python
python 使用递归回溯完美解决八皇后的问题
2020/02/26 Python
通过代码实例解析Pytest运行流程
2020/08/20 Python
Python+unittest+requests 接口自动化测试框架搭建教程
2020/10/09 Python
美国单身专业人士在线约会网站:EliteSingles
2019/03/19 全球购物
中国入世承诺
2014/04/01 职场文书
消防宣传口号
2014/06/16 职场文书
应急处置方案
2014/06/16 职场文书
授权委托书公证
2014/09/14 职场文书
小学生自我评价100字(15篇)
2014/09/18 职场文书
高校自主招生校长推荐信
2015/03/23 职场文书
Python基础之函数嵌套知识总结
2021/05/23 Python
Python Matplotlib绘制条形图的全过程
2021/10/24 Python