jQuery 源码分析(十八) ready事件详解
ready事件是当DOM文档树加载完成后执行一个函数(不包含图片,css等),因此它的触发要早于load事件。用法:
- $(document).ready(fun) ;fun是一个函数,这样当DOM树加载完毕后就会执行该匿名函数了
ready有一个简写,可以直接传入$(fun)即可,这是因为在jQuey内部也定义了一个$(document)的jQuery对象,和我们在上面的写法是一样的
ready事件和window的onload区别:
- ready事件 ;等dom树载完毕后就可以执行
- onload事件 ;等网页中所有的资源加载完毕后(包括图片,flash,音频,视频)才能执行
onload事件还可以绑定在某个图片上面,举个例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
<img src="https://www.cnblogs.com/images/logo_small.gif" alt="">
<script>
$(()=>console.log('DOM树已加载完毕')) //ready事件
$('img').on('load',()=>console.log('图片已加载完毕')) //图片的加载事件
$(window).on('load',()=>console.log('资源已加载完毕')) //网页所有资源都加载完毕后的事件
</script>
</body>
</html>
这里我们用了箭头函数来写,代码很简单了,我们在绑定了一个ready事件,一个图片上的onload事件和window上的onload事件,加载后输出如下:
可以看到首先是ready事件的触发,然后是图片的onload事件,最后是window的onload事件的触发,此时所有资源都已经加载完了
源码分析
jquery的ready事件就是在document上绑定了一个DOMContentLoaded事件对象,对他进行了一下封装,DOMContentLoaded事件的原理可以看看看这篇文章,介绍得挺详细的:https://www.cnblogs.com/caizhenbo/p/6679478.html
jQuery的ready事件是基于函数列表实现的,函数列表可以看这个连接:https://www.cnblogs.com/greatdesert/p/11433365.html
当我们调用$(fun)去执行一个ready事件的时候首先会执行入口模块里的逻辑,与ready相关的如下:
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc; // Handle $(""), $(null), or $(undefined)
if ( !selector ) {
return this;
} // Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
} // The body element only exists once, optimize finding it
if ( selector === "body" && !context && document.body ) {
this.context = document;
this[0] = document.body;
this.selector = selector;
this.length = 1;
return this;
} // Handle HTML strings
if ( typeof selector === "string" ) {
/*略*/
} else if ( jQuery.isFunction( selector ) ) { //如果参数selector是函数,则认为是绑定ready事件
return rootjQuery.ready( selector ); //则执行rootjQuery.ready()方法,并把selector作为参数传入
} /*略*/
},
rootjQuery是jQuery内部定义的一个局部变量,是一个jQuery实例,如下:
rootjQuery = jQuery(document); //第917行,保存了document对象引用的jQuery实例
在入口模块引用rootjQuery.ready()也就是执行了rootjQuery实例对象上的ready方法(该方法是定义在原型上的),如下:
jQuery.fn = jQuery.prototype = {
ready: function( fn ) {
// Attach the listeners
jQuery.bindReady(); //先执行jQuery.bindReady()绑定ready事件(实际上绑定的是DOMContentLoaded或onreadystatechange事件) // Add the callback
readyList.add( fn ); //为函数列表readyList增加一个函数 return this;
}
}
jQuery.bindReady()是一个静态方法,用于绑定事件的,内部会初始化readyList为一个jQuery.Callbacks( "once memory" )函数列表对象
然后执行readyList.add( fn )将fn函数保存到函数列表readyList里面。
jQuery.bindReady()的实现如下:
jQuery.extend({
bindReady: function() { //初始化ready事件监听函数列表readyList,并为document对象绑定ready事件主监听函数DOMContentLoaded
if ( readyList ) {
return;
} readyList = jQuery.Callbacks( "once memory" ); //调用jQuery.Callbacks(flags)ready事件监听函数列表readylist,同时传入once和memory标记。 // Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) { //如果文档已经就绪,则调用jQuery.ready(wait)执行ready事件监听函数列表readyList
// Handle it asynchronously to allow scripts the opportunity to delay ready
return setTimeout( jQuery.ready, 1 ); //通过setTimeout()异步执行方法jQuery.ready(wait),以允许其他脚本延迟ready事件的触发。
} // Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) { //在IE9+及以上浏览器绑定DOMContentLoaded事件
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); //把监听函数DOMContentLoaded绑定到document对象的DOMContentLoaded事件上 // A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false ); // If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready ); // If IE and not a frame
// continually check to see if the document is ready
var toplevel = false; try {
toplevel = window.frameElement == null;
} catch(e) {} if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
},
/*略*/
})
这里我们调用document.addEventListener在document上绑定了一个DOMContentLoaded事件,这样当DOM树加载完后就会执行DOMContentLoaded函数了,DOMContentLoaded函数的定义如下:
if ( document.addEventListener ) { //如果是IE9+和其他浏览器
DOMContentLoaded = function() {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); //先移除document的DOMContentLoaded事件
jQuery.ready(); //再调用jQuery.ready()执行ready事件监听函数
}; } else if ( document.attachEvent ) {
DOMContentLoaded = function() {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", DOMContentLoaded );
jQuery.ready();
}
};
}
函数内首先会移除DOMContentLoaded事件,然后调用jQuery.ready()事件,这是DOM树触发后的事件了(我们在jQuery.fn.ready()内执行了readyList.add( fn )增加的函数都会依次触发),如下:
jQuery.extend({
isReady: false,
ready: function( wait ) { //实际执行的函数 触发ready事件监听函数列表readyList和数据缓存对象中的ready事件监听函数。
// Either a released hold or an DOMready/load event and not yet ready
if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { //如果wait是true且jQuery.readyWait等于0 或者 wait不是true且jQuery.isReady是false 则执行 初始化jQuery.isReady为false的
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( !document.body ) {
return setTimeout( jQuery.ready, 1 );
} // Remember that the DOM is ready
jQuery.isReady = true; //设置jQuery.inReady为true,表示ready事件已就绪。 // If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
} // If there are functions bound, to execute
readyList.fireWith( document, [ jQuery ] ); //执行ready事件监听函数readyList,上下文是document(即关键词this),[jQuery]是ready事件监听函数的参数。 // Trigger any bound ready events
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger( "ready" ).off( "ready" );
}
}
},
/*略*/
})
writer by:大沙漠 QQ:22969969
最后调用readyList.fireWith()方法去触发回掉函数列表里的每个函数。
jQuery 源码分析(十八) ready事件详解的更多相关文章
- jQuery 源码分析(十一) 队列模块 Queue详解
队列是常用的数据结构之一,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队).特点是先进先出,最先插入的元素最先被删除. 在jQuery内部,队列模块为动画模块提供基 ...
- mybatis 源码分析(八)ResultSetHandler 详解
本篇博客就是 myabtis 系列的最后一篇了,还剩 ResultSetHandler 没有分析:作为整个 mybatis 最复杂最繁琐的部分,我不打算按步骤一次详解,因为里面的主要内容就是围绕 re ...
- netty源码分析(十八)Netty底层架构系统总结与应用实践
一个EventLoopGroup当中会包含一个或多个EventLoop. 一个EventLoop在它的整个生命周期当中都只会与唯一一个Thread进行绑定. 所有由EventLoop所处理的各种I/O ...
- jQuery 源码分析(十六) 事件系统模块 底层方法 详解
jQuery事件系统并没有将事件监听函数直接绑定到DOM元素上,而是基于数据缓存模块来管理监听函数的,事件模块代码有点多,我把它分为了三个部分:分底层方法.实例方法和便捷方法.ready事件来讲,好理 ...
- jQuery 源码分析(十) 数据缓存模块 data详解
jQuery的数据缓存模块以一种安全的方式为DOM元素附加任意类型的数据,避免了在JavaScript对象和DOM元素之间出现循环引用,以及由此而导致的内存泄漏. 数据缓存模块为DOM元素和JavaS ...
- jQuery 源码分析(十二) 数据操作模块 html特性 详解
jQuery的属性操作模块总共有4个部分,本篇说一下第1个部分:HTML特性部分,html特性部分是对原生方法getAttribute()和setAttribute()的封装,用于修改DOM元素的特性 ...
- jQuery 源码分析(十九) DOM遍历模块详解
jQuery的DOM遍历模块对DOM模型的原生属性parentNode.childNodes.firstChild.lastChild.previousSibling.nextSibling进行了封装 ...
- jQuery 源码分析(十五) 数据操作模块 val详解
jQuery的属性操作模块总共有4个部分,本篇说一下最后一个部分:val值的操作,也是属性操作里最简单的吧,只有一个API,如下: val(vlaue) ;获取匹配元素集合中第一个元素的 ...
- jQuery 源码分析(十四) 数据操作模块 类样式操作 详解
jQuery的属性操作模块总共有4个部分,本篇说一下第3个部分:类样式操作部分,用于修改DOM元素的class特性的,对于类样式操作来说,jQuery并没有定义静态方法,而只定义了实例方法,如下: a ...
随机推荐
- liunxCPU和内存,磁盘等资源
1.Screen是一款由GNU计划开发的用于命令行终端切换的自由软件.用户可以通过该软件同时连接多个本地或远程的命令行会话,并在其间自由切换.GNU Screen可以看作是窗口管理器的命令行界面版本. ...
- element-ui 中Switch的用法
在element-ui中,如果你想知道Switch是开还是关,使用事件 @change="getchange(value2)" 它会输出true或者false.true代表的是开, ...
- luoguP1871 对撞机【赛后第一题
题面 题目描述 在2312年,宇宙中发现了n台巨型对撞机,这些对撞机分别用1-n的自然数标识.科学家们不知道启动这些对撞机会发生什么危险事故,所以这些机器,刚开始都是出于关闭的状态. 随着科学家们的研 ...
- 推荐系统| ② 离线推荐&基于隐语义模型的协同过滤推荐
一.离线推荐服务 离线推荐服务是综合用户所有的历史数据,利用设定的离线统计算法和离线推荐算法周期性的进行结果统计与保存,计算的结果在一定时间周期内是固定不变的,变更的频率取决于算法调度的频率. 离线推 ...
- MySql-8.0.16-winx64 安装
参考文章: https://www.cnblogs.com/lxlin/p/9635350.html https://www.cnblogs.com/xc1234/p/9050149.html MyS ...
- python 对字典分别按照key值、value值进行排序
1.sorted函数首先介绍sorted函数,sorted(iterable,key,reverse),sorted一共有iterable,key,reverse这三个参数. 其中iterable表示 ...
- .netcore控制台->定时任务Quartz
之前做数据同步时,用过timer.window服务,现在不用那么费事了,可以使用Quartz,并且配置灵活,使用cron表达式配置XML就可以.我用的是3.0.7版本支持.netcore. 首先创建一 ...
- JS基础语法---总结
JS是一门什么样的语言? 是一门解释性的语言 是一门脚本语言 是一门弱类型语言,声明变量都用var 是一门基于对象的语言 是一门动态类型的语言: 1. 代码(变量)只有执行到这个 ...
- Linux系统学习 一、安装,调试
环境 主机: Windows 10 虚拟机: VMware 15 Pro 镜像: 一.安装过程: 然后开启虚拟机 设置主机名 时区 密码 最小安装 等着 重启 登录 二.配置静态IP地址 输入ifco ...
- 使用vue-cli搭建spa项目
1. 什么是vue-cli? vue-cli是vue.js的脚手架,用于自动生成vue.js+webpack的项目模板,创建命令如下: vue init webpack xxx 注1:xxx 为自己创 ...