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 相关文章推荐
CSS+Table图文混排中实现文本自适应图片宽度(超简单+跨所有浏览器)
Feb 14 Javascript
用js来解决ajax读取页面乱码
Nov 28 Javascript
屏蔽script注入小例子
Nov 12 Javascript
jquery删除指定子元素代码实例
Jan 13 Javascript
js正则表达式匹配数字字母下划线等
Apr 14 Javascript
JS实现仿新浪黄色经典滑动门效果代码
Sep 27 Javascript
jQuery插件之Tocify动态节点目录菜单生成器附源码下载
Jan 08 Javascript
JavaScript中数组Array.sort()排序方法详解
Mar 01 Javascript
JavaScript中set与get方法用法示例
Aug 15 Javascript
微信小程序左滑删除功能开发案例详解
Nov 12 Javascript
Element-ui el-tree新增和删除节点后如何刷新tree的实例
Aug 31 Javascript
AngularJS实现多级下拉框
Mar 25 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采集利器 Snoopy 试用心得
2011/07/03 PHP
解析PHP跳出循环的方法以及continue、break、exit的区别介绍
2013/07/01 PHP
一个PHP实现的轻量级简单爬虫
2015/07/08 PHP
Javascript hasOwnProperty 方法 &amp; in 关键字
2008/11/26 Javascript
利用JS重写Cognos右键菜单的实现代码
2010/04/11 Javascript
js动态给table添加/删除tr的方法
2013/08/02 Javascript
JS弹出可拖拽可关闭的div层完整实例
2015/02/13 Javascript
使用PHP+JavaScript将HTML页面转换为图片的实例分享
2016/04/18 Javascript
vue.js 表格分页ajax 异步加载数据
2016/10/18 Javascript
jQuery如何跳转到另一个网页 就这么简单
2016/12/28 Javascript
JS正则截取两个字符串之间及字符串前后内容的方法
2017/01/06 Javascript
nodeJs链接Mysql做增删改查的简单操作
2017/02/04 NodeJs
Node.js+ES6+dropload.js实现移动端下拉加载实例
2017/06/01 Javascript
vue中echarts3.0自适应的方法
2018/02/26 Javascript
vue中element-ui表格缩略图悬浮放大功能的实例代码
2018/06/26 Javascript
layui 表格操作列按钮动态显示的实现方法
2019/09/06 Javascript
[01:07:17]EG vs Optic Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
Python实现备份文件实例
2014/09/16 Python
Django数据库表反向生成实例解析
2018/02/06 Python
Python扩展内置类型详解
2018/03/26 Python
python opencv实现切变换 不裁减图片
2018/07/26 Python
使用Python获取并处理IP的类型及格式方法
2018/11/01 Python
python爬虫获取新浪新闻教学
2018/12/23 Python
python 密码学示例——凯撒密码的实现
2020/09/21 Python
css3简单练习实现遨游浏览器logo的绘制
2013/01/30 HTML / CSS
HTML5中的网络存储实现方式
2020/04/28 HTML / CSS
韩国CJ食品专卖网:CJonmart
2016/09/11 全球购物
锐步香港官方网上商店:Reebok香港
2020/11/05 全球购物
党员年终民主评议的自我评价
2013/11/05 职场文书
大学生自助营养快餐店创业计划书
2014/01/13 职场文书
20年同学聚会邀请函
2014/02/04 职场文书
旅游管理专业大学生职业规划书
2014/02/27 职场文书
2014年服务员工作总结
2014/11/18 职场文书
幼儿园万圣节活动总结
2015/05/05 职场文书
python 详解turtle画爱心代码
2022/02/15 Python
nginx搭建NFS网络文件系统
2022/04/14 Servers