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实现input输入框实时输入触发事件代码
Jan 28 Javascript
jquery实现的随机多彩tag标签随机颜色和字号大小效果
Mar 27 Javascript
AngularJS实现标签页的两种方式
Sep 05 Javascript
详解vue-cli + webpack 多页面实例应用
Apr 25 Javascript
如何用webpack4带你实现一个vue的打包的项目
Jun 20 Javascript
在axios中使用params传参的时候传入数组的方法
Sep 25 Javascript
vue-cli3+typescript初体验小结
Feb 28 Javascript
小程序云开发如何实现图片上传及发表文字
May 17 Javascript
史上最为详细的javascript继承(推荐)
May 18 Javascript
使用xampp将angular项目运行在web服务器的教程
Sep 16 Javascript
JavaScript实现简单进度条效果
Mar 25 Javascript
VUE子组件向父组件传值详解(含传多值及添加额外参数场景)
Sep 01 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桌面中心(四) 数据显示
2007/03/11 PHP
mac下多个php版本快速切换的方法
2016/10/09 PHP
JavaScript 在线压缩和格式化收藏
2009/01/16 Javascript
JSON序列化与解析原生JS方法且IE6和chrome测试通过
2013/09/05 Javascript
对JavaScript中this指针的新理解分享
2015/01/31 Javascript
谈谈基于iframe、FormData、FileReader三种无刷新上传文件的方法
2015/12/03 Javascript
js操作数据库实现注册和登陆的简单实例
2016/05/26 Javascript
Bootstrap开发实战之响应式轮播图
2016/06/02 Javascript
javascript 删除数组元素和清空数组的简单方法
2017/02/24 Javascript
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
2017/05/30 Javascript
jquery.validate表单验证插件使用详解
2017/06/21 jQuery
浅谈js的解析顺序 作用域 严格模式
2017/10/23 Javascript
Angular4 组件通讯方法大全(推荐)
2018/07/12 Javascript
在vue中使用express-mock搭建mock服务的方法
2018/11/07 Javascript
vue实例的选项总结
2020/06/09 Javascript
微信小程序将页面按钮悬浮固定在底部的实现代码
2020/10/29 Javascript
vue点击Dashboard不同内容 跳转到同一表格的实例
2020/11/13 Javascript
python实现排序算法
2014/02/14 Python
基于wxpython实现的windows GUI程序实例
2015/05/30 Python
python excel使用xlutils类库实现追加写功能的方法
2018/05/02 Python
Python爬虫小技巧之伪造随机的User-Agent
2018/09/13 Python
python判断计算机是否有网络连接的实例
2018/12/15 Python
使用Django2快速开发Web项目的详细步骤
2019/01/06 Python
使用Windows批处理和WMI设置Python的环境变量方法
2019/08/14 Python
python运用pygame库实现双人弹球小游戏
2019/11/25 Python
关于Keras Dense层整理
2020/05/21 Python
Python如何避免文件同名产生覆盖
2020/06/09 Python
Python如何将字符串转换为日期
2020/07/31 Python
德国运动鞋网上商店:Afew Store
2018/01/05 全球购物
迪奥美国官网:Dior美国
2019/12/07 全球购物
大学生职业生涯设计书
2014/01/02 职场文书
李开复演讲稿
2014/05/24 职场文书
学校消防安全责任书
2014/07/23 职场文书
2016思想纪律作风整顿心得体会
2016/01/23 职场文书
MySQL 重命名表的操作方法及注意事项
2021/05/21 MySQL
MySQL中JOIN连接的基本用法实例
2022/06/05 MySQL