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拖拽排序效果实现代码
Sep 20 Javascript
js获取触发事件元素在整个网页中的绝对坐标(示例代码)
Dec 13 Javascript
javascript向后台传送相同属性的参数即数组参数
Feb 17 Javascript
JavaScript在网页中画圆的函数arc使用方法
Nov 13 Javascript
jQuery判断是否存在滚动条的简单方法
Sep 17 Javascript
Bootstrap基本组件学习笔记之面板(14)
Dec 08 Javascript
vuejs父子组件通信的问题
Jan 11 Javascript
validationEngine 表单验证插件使用实例代码
Jun 15 Javascript
JavaScript Drum Kit 指南(纯 JS 模拟敲鼓效果)
Jul 23 Javascript
详解Koa中更方便简单发送响应的方式
Jul 20 Javascript
Vue源码解读之Component组件注册的实现
Aug 24 Javascript
Node.js如何优雅的封装一个实用函数的npm包的方法
Apr 29 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/10/09 PHP
一段防盗连的PHP代码
2006/12/06 PHP
php购物车实现代码
2011/10/10 PHP
PHP使用数组依次替换字符串中匹配项
2016/01/08 PHP
PHP常见的6个错误提示及解决方法
2016/07/07 PHP
php版微信公众号接口实现发红包的方法
2016/10/14 PHP
PHP基于phpqrcode类生成二维码的方法详解
2018/03/14 PHP
PHP论坛实现积分系统的思路代码详解
2020/06/01 PHP
ExtJS扩展 垂直tabLayout实现代码
2009/06/21 Javascript
图像替换新技术 状态域方法
2010/01/28 Javascript
编写可维护面向对象的JavaScript代码[翻译]
2011/02/12 Javascript
JS截取url中问号后面参数的值信息
2014/04/29 Javascript
JavaScript中的全局对象介绍
2015/01/01 Javascript
jQuery获取checkboxlist的value值的方法
2015/09/27 Javascript
基于JS如何实现类似QQ好友头像hover时显示资料卡的效果(推荐)
2016/06/09 Javascript
javascript动画系列之模拟滚动条
2016/12/13 Javascript
JS图片延迟加载插件LazyImgv1.0用法分析【附demo源码下载】
2017/09/04 Javascript
vue生命周期与钩子函数简单示例
2019/03/13 Javascript
微信小程序template模板与component组件的区别和使用详解
2019/05/22 Javascript
JavaScript this在函数中的指向及实例详解
2019/10/14 Javascript
Node.js API详解之 vm模块用法实例分析
2020/05/27 Javascript
把大数据数字口语化(python与js)两种实现
2013/02/21 Python
python3大文件解压和基本操作
2017/12/15 Python
详谈python3 numpy-loadtxt的编码问题
2018/04/29 Python
对Python 窗体(tkinter)树状数据(Treeview)详解
2018/10/11 Python
Jupyter Notebook添加代码自动补全功能的实现
2021/01/07 Python
纯css3(无图片/js)制作的几个社交媒体网站的图标
2013/03/21 HTML / CSS
高性能钓鱼服装:Huk Gear
2019/02/20 全球购物
标准导师推荐信(医学类)
2013/10/28 职场文书
《锄禾》教学反思
2014/04/08 职场文书
《祁黄羊》教学反思
2014/04/22 职场文书
跳槽求职信范文
2014/05/26 职场文书
教导处教学工作总结
2015/08/12 职场文书
二年级作文之动物作文
2019/11/13 职场文书
Python MNIST手写体识别详解与试练
2021/11/07 Python
《艾尔登法环》1.03.3补丁上线 碎星伤害调整
2022/04/07 其他游戏