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 相关文章推荐
html 锁定页面(js遮罩层弹出div效果)
Oct 27 Javascript
javascript确认框的三种使用方法
Dec 17 Javascript
javascritp添加url参数将参数加入到url中
Sep 25 Javascript
jquery-tips悬浮提示插件分享
Jul 31 Javascript
高性能JavaScript 重排与重绘(2)
Aug 11 Javascript
Javascript中关于Array.filter()的妙用详解
Dec 04 Javascript
详解Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成)
Apr 20 Javascript
Vue源码之关于vm.$delete()/Vue.use()内部原理详解
May 01 Javascript
D3.js(v3)+react 实现带坐标与比例尺的柱形图 (V3版本)
May 09 Javascript
Layui数据表格 前后端json数据接收的方法
Sep 19 Javascript
抖音短视频(douyin)去水印工具的实现代码
Mar 30 Javascript
vue/cli 配置动态代理无需重启服务的方法
May 20 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 ignore_user_abort与register_shutdown_function 使用方法
2009/06/14 PHP
查找php配置文件php.ini所在路径的二种方法
2014/05/26 PHP
PHP实现的多彩标签效果代码分享
2014/08/21 PHP
为PHP安装imagick时出现Cannot locate header file MagickWand.h错误的解决方法
2014/11/03 PHP
PHP HTTP 认证实例详解
2016/11/03 PHP
Yii框架通过请求组件处理get,post请求的方法分析
2019/09/03 PHP
js的with语句使用方法
2007/09/21 Javascript
一个网马的tips实现分析
2010/11/28 Javascript
juqery 学习之四 筛选过滤
2010/11/30 Javascript
使用js的replace()方法查找字符示例代码
2013/10/28 Javascript
Jquery中ajax方法data参数的用法小结
2014/02/12 Javascript
Javascript学习笔记之数组的遍历和 length 属性
2014/11/23 Javascript
js获取页面description的方法
2015/05/21 Javascript
JavaScript中this详解
2015/09/01 Javascript
详解Javascript模板引擎mustache.js
2016/01/20 Javascript
js控件Kindeditor实现图片自动上传功能
2020/07/20 Javascript
详解Angular 4 表单快速入门
2017/06/05 Javascript
Vue2.0 事件的广播与接收(观察者模式)
2018/03/14 Javascript
vue+axios+mock.js环境搭建的方法步骤
2018/08/28 Javascript
使用Vue-cli 中为单独页面设置背景图片铺满全屏
2020/07/17 Javascript
[01:09:13]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第三场 1月19日
2021/03/11 DOTA
Tensorflow中使用tfrecord方式读取数据的方法
2018/06/19 Python
Python基于scipy实现信号滤波功能
2019/05/08 Python
django框架实现一次性上传多个文件功能示例【批量上传】
2019/06/19 Python
PyQt5基本控件使用详解:单选按钮、复选框、下拉框
2019/08/05 Python
如何利用pygame实现简单的五子棋游戏
2019/12/29 Python
Python面向对象原理与基础语法详解
2020/01/02 Python
Django权限控制的使用
2021/01/07 Python
CSS3样式linear-gradient的使用实例
2017/01/16 HTML / CSS
L’urv官网:精品女性运动服品牌
2019/07/07 全球购物
大学生军训自我鉴定
2014/02/12 职场文书
保护动物倡议书
2014/04/15 职场文书
幼儿园大班家长评语
2014/04/17 职场文书
新教师培训方案
2014/06/08 职场文书
客户答谢会活动方案
2014/08/31 职场文书
MYSQL数据库使用UTF-8中文编码乱码的解决办法
2021/05/26 MySQL