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 面向对象继承
Nov 26 Javascript
Yii-自定义删除确认弹框(zyd)jquery实现代码
Mar 04 Javascript
如何使用jQUery获取选中radio对应的值(一句代码)
Jun 03 Javascript
将字符串中由空格隔开的每个单词首字母大写
Apr 06 Javascript
一个可以增加和删除行的table并可编辑表格中内容
Jun 16 Javascript
浅谈Jquery为元素绑定事件
Apr 27 Javascript
在JavaScript中操作时间之getUTCDate()方法的使用
Jun 10 Javascript
JS组件系列之MVVM组件构建自己的Vue组件
Apr 28 Javascript
深入理解JavaScript继承的多种方式和优缺点
May 12 Javascript
关于定制FileField中的上传文件名称问题
Aug 22 Javascript
jQuery实现checkbox全选、反选及删除等操作的方法详解
Aug 02 jQuery
vue实现手机号码的校验实例代码(防抖函数的应用场景)
Sep 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
PHP生成静态页
2006/11/25 PHP
分享一个php 的异常处理程序
2014/06/22 PHP
php中的字符编码转换函数用法示例
2014/10/20 PHP
php使用Jpgraph绘制柱形图的方法
2015/06/10 PHP
ThinkPHP实现静态缓存和动态缓存示例代码
2017/05/02 PHP
解决php扩展安装不生效问题
2019/10/25 PHP
JavaScript中的其他对象
2008/01/16 Javascript
jquery validation验证身份证号,护照,电话号码,email(实例代码)
2013/11/06 Javascript
jquery实现仿Flash的横向滑动菜单效果代码
2015/09/17 Javascript
Bootstrap Paginator分页插件使用方法详解
2016/05/30 Javascript
前端实现文件的断点续传(前端文件提交+后端PHP文件接收)
2016/11/04 Javascript
JavaScript中如何使用cookie实现记住密码功能及cookie相关函数介绍
2016/11/10 Javascript
JavaScript运动框架 链式运动到完美运动(五)
2017/05/18 Javascript
JS实现多物体运动的方法详解
2018/01/23 Javascript
nodejs实现连接mongodb数据库的方法示例
2018/03/15 NodeJs
nodejs读取本地中文json文件出现乱码解决方法
2018/10/10 NodeJs
JavaScript中的this妙用实例分析
2020/05/09 Javascript
实例分析javascript中的异步
2020/06/02 Javascript
python Django连接MySQL数据库做增删改查
2013/11/07 Python
python 中if else 语句的作用及示例代码
2018/03/05 Python
Win10下python3.5和python2.7环境变量配置教程
2018/09/18 Python
Python 经典面试题 21 道【不可错过】
2018/09/21 Python
Python基于opencv实现的简单画板功能示例
2019/03/04 Python
python爬虫实现中英翻译词典
2019/06/25 Python
django的聚合函数和aggregate、annotate方法使用详解
2019/07/23 Python
Lancome兰蔻官方旗舰店:来自法国的世界知名美妆品牌
2018/06/14 全球购物
初二物理教学反思
2014/01/29 职场文书
收银出纳员岗位职责
2014/02/23 职场文书
反腐倡廉标语
2014/06/24 职场文书
机关干部个人对照检查材料思想汇报
2014/09/28 职场文书
事业单位财务人员岗位职责
2015/04/14 职场文书
消防安全培训工作总结
2015/10/23 职场文书
小学作文之描写天气
2019/08/15 职场文书
《水浒传》读后感3篇(范文)
2019/09/19 职场文书
Python中可变和不可变对象的深入讲解
2021/08/02 Python
Go Plugins插件的实现方式
2021/08/07 Golang