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 相关文章推荐
VBScript版代码高亮
Jun 26 Javascript
Jquery中国地图热点效果-鼠标经过弹出提示层信息的简单实例
Feb 12 Javascript
javascript动态向网页中添加表格实现代码
Feb 19 Javascript
jquery使用经验小结
May 20 Javascript
vue中渐进过渡效果实现
Oct 27 Javascript
React实现点击删除列表中对应项
Jan 10 Javascript
jQuery实现单击按钮遮罩弹出对话框效果(2)
Feb 20 Javascript
详解webpack+es6+angular1.x项目构建
May 02 Javascript
纯js实现的积木(div层)拖动功能示例
Jul 19 Javascript
浅谈Webpack 持久化缓存实践
Mar 22 Javascript
解决vue.js中settimeout遇到的问题(时间参数短效果不稳定)
Jul 21 Javascript
Vue Elenent实现表格相同数据列合并
Nov 30 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
php 修改zen-cart下单和付款流程以防止漏单
2010/03/08 PHP
开启CURL扩展,让服务器支持PHP curl函数(远程采集)
2011/03/19 PHP
深入PHP数据缓存的使用说明
2013/05/10 PHP
基于PHP文件操作的详解
2013/06/05 PHP
php缓冲 output_buffering的使用详解
2013/06/13 PHP
关于zend studio 出现乱码问题的总结
2013/06/23 PHP
php实现批量删除挂马文件及批量替换页面内容完整实例
2016/07/08 PHP
在Laravel 中实现是否关注的示例
2019/10/22 PHP
javascript实现颜色渐变的方法
2013/10/30 Javascript
当json键为数字时的取值方法解析
2013/11/15 Javascript
JavaScript中的方法调用详细介绍
2014/12/30 Javascript
js实现从数组里随机获取元素
2015/01/12 Javascript
javascript将异步校验表单改写为同步表单
2015/01/27 Javascript
使用jquery实现仿百度自动补全特效
2015/07/23 Javascript
原生js开发的日历插件
2017/02/04 Javascript
关于jQuery EasyUI 中刷新Tab选项卡后一个页面变形的解决方法
2017/03/02 Javascript
JS鼠标滚动分页效果示例
2017/07/05 Javascript
vue router自动判断左右翻页转场动画效果
2017/10/10 Javascript
动态加载JavaScript文件的3种方式
2018/05/05 Javascript
Vue中使用sass实现换肤功能
2018/09/07 Javascript
tsconfig.json配置详解
2019/05/17 Javascript
JavaScript实现左右滚动电影画布
2020/02/06 Javascript
[00:44]TI7不朽珍藏III——军团指挥官不朽展示
2017/07/15 DOTA
详解Django+Uwsgi+Nginx的生产环境部署
2018/06/25 Python
Python装饰器使用你可能不知道的几种姿势
2019/10/25 Python
python 解决flask uwsgi 获取不到全局变量的问题
2019/12/22 Python
Python 日期的转换及计算的具体使用详解
2020/01/16 Python
Python3通过chmod修改目录或文件权限的方法示例
2020/06/08 Python
Python+MySQL随机试卷及答案生成程序的示例代码
2021/02/01 Python
python 如何用urllib与服务端交互(发送和接收数据)
2021/03/04 Python
CSS3区域模块region相关编写示例
2015/08/28 HTML / CSS
加拿大户外探险购物网站:SAIL
2020/06/27 全球购物
2014年党员自我评议(5篇)
2014/09/12 职场文书
教师党员个人整改措施材料
2014/09/16 职场文书
党员反腐倡廉学习心得体会
2015/08/15 职场文书
2016年十一促销广告语
2016/01/28 职场文书