jquery源码 DOM加载
jQuery版本:2.0.3
DOM加载有关的扩展
- isReady:DOM是否加载完(内部使用)
- readyWait:等待多少文件的计数器(内部使用)
- holdReady():推迟DOM触发
- ready():准备DOM触发。
- jQuery.ready.promise=function(){}; 监听DOM的异步操作(内部使用)
一、$(function(){})和原生window.onload的关系
这个在面试中也是经常会被问到的。从下面几个角度来分析一下它们的区别
1、执行时机
页面加载,先加载节点,再加载文件,比如img文件,flash等。
$(function(){})DOM加载完执行。可能DOM元素关联的东西并没有加载完。
window.onload等节点和文件都加载完执行。
对应的事件监听
jQuery用的是DOMContentLoaded事件。
DOMDContentLoaded:原生DOM加载事件,这个事件触发代表DOM加载完了。
我之前写过一篇文章的页面加载时间分析里也有提到。
onload对应的是load事件。
2、个数
window.onload不能写多个,后面的会覆盖前面的。
$(function(){})可以写多个。都会执行 。
3、简化写法
$(function(){})是$(document) .ready(function(){});的简化写法。
window.onload没有简化写法。
二、jQurey如何实现DOM ready的
jQuery直接调用DOMContentLoaded来实现DOM的ready。但是DOMContentLoaded和onLoad一样,浏览器只执行一次,jQuery用什么判断是否已经执行过呢?document.readyState就是判断这个的依据。
readyState是document的属性,总共有3个值:
- loading:文档正在加载中
- interactive:文档已经加载完成,正在进行css和图片等资源的加载
- complete:文档的所以资源加载完成
判断完之后如何回调呢?就是用Promise。jQuery通过new一个$.Deferred(promise)对象来实现对DOM的ready的回调,在DOMContentLoaded中将这个promise给resolve掉,这样就执行了之前注册的回调函数,同时后面新注册的回调也会立刻执行。
但是在调用promise之前,jQuery执行了一次setTimeout,因为jQuery.Promise是不会产生异步的,这和标准的promise规范是不一样的,所有jQuery自己又手动做了一次setTimeout来实现异步。这样使得无论使用在DOM的ready之前注册的回调还是之后注册的回调都会在异步中执行。
三、源码整体实现逻辑
$(fn)==>new一个 jQuery.fn.init(fn)==>返回$(document).ready( fn)。也就是说
- $(function(){}) =》
- 调用$(document).ready(function(){})=》
- 相当于$().ready(fn)实例方法=》
- 调用的jQuery.ready.promise().done(fn)=》
- jQuery.ready.promise中不管if还是else最终都是调用jQuery.ready(),并返回promise=》
- jQuery.ready()里面重点是readyList.resolveWith( document, [ jQuery ] );已完成。至此DOM加载完毕就可以调用fn了。
四、实现细节
1、重点是:jQuery.ready.promise()方法【巧妙】
如果DOM已经加载完成了,调用jQuery.ready()这个工具方法;
如果DOM没加载完,监听DOMContentLoaded事件和load事件,等事件发生时回调completed(),最终也是调用jQuery.ready()这个工具方法;
var // A central reference to the root jQuery(document) rootjQuery,// The deferred used on DOM ready readyList;jQuery.ready.promise = function( obj ) {if ( !readyList ) { //第一次readyList为空可以进来,后续就进不来if了,只执行一次 readyList = jQuery.Deferred(); //第一步,创建延迟对象if ( document.readyState === "complete" ) { //DOM加载完成的标志就是document.readyState为complete,如果DOM已经加载好了就直接调工具方法jQuery.ready。setTimeout( jQuery.ready );//加定时器是为了兼容IE} else {//DOM没有加载完检测,即检测了DOMContentLoaded事件,也检测了load事件;最终走回调completed函数// Use the handy event callbackdocument.addEventListener( "DOMContentLoaded", completed, false );// A fallback to window.onload, that will always workwindow.addEventListener( "load", completed, false ); //因为火狐浏览器会缓存load事件,为了第一时间相应所以对load也监听了 }}return readyList.promise( obj ); };
completed回调函数如下,最终调用的也是jQuery.ready()。
// The ready event handler and self cleanup methodcompleted = function() {//不管是DOMContentLoaded事件还是load发生,都会取消2个事件监听//jQuery.ready()只会触发一次document.removeEventListener( "DOMContentLoaded", completed, false );window.removeEventListener( "load", completed, false );jQuery.ready();};
2、jQuery.ready()工具方法做了些什么
先做个测试:
$(function(arg){alert(this); //[object HTMLDocument]alert(arg); //jQuery函数})
再做个测试:
除了$(function(){});$(document).ready(function(){}),也可以把ready当做事件来处理如下。
<script> $(document).on("ready",function(){alert(123); //123 }); </script>
之所以会自动弹出123,是因为在jQuery源码中用这句话jQuery( document ).trigger("ready").off("ready");来主动触发了ready事件,触发后再取消掉。
// Handle when the DOM is ready ready: function( wait ) { //参数和holdReady有关// Abort if there are pending holds or we're already readyif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {return;}// Remember that the DOM is readyjQuery.isReady = true;// If a normal DOM Ready event fired, decrement, and wait if need beif ( wait !== true && --jQuery.readyWait > 0 ) {return;}//第一步看这里重点,resolveWith改变状态的时候传参了,给done中方法fn传入了参数,//document是fn的this指向,jQuery是参数// If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] );//跟主动触发有关// Trigger any bound ready eventsif ( jQuery.fn.trigger ) {jQuery( document ).trigger("ready").off("ready");} },
跟ready的参数有关的有一个holdReady()。
先做个测试
$.holdReady(true); $(function () {alert(123); //调用了holdReady并传参true,就不能弹出123了 });
可以推迟,也可以释放推迟,释放了以后就可以触发了。
$.holdReady(true); $.holdReady(false); $(function () {alert(123); //释放了holdReady,就弹出123 });
这个有什么用?
比如:
$.getScript('js/a.js',function(){ //异步加载,不会影响后续代码执行。可能会产生一个问题,alert(2)先执行了a.js还没有加载完 })$(function () {alert(2);//先弹2,后弹出1 });
很多时候引入外部文件的时候,都想等外部文件或者插件加载完,再去触发操作,操作可能用到a.js。现在这个顺序不对,会出问题。
怎样解决这个问题?用holdReady()方法。
$.holdReady(true); //在这里先hold住$.getScript('js/a.js', function () { //异步加载,不会影响后续代码执行。可能会产生一个问题,alert(2)先执行了a.js还没有加载完$.holdReady(false); //加载完释放,不hold了就可以弹2了 })$(function () {alert(2);//先弹2,后弹出1});
再深入一点,holdReady() 要针对的文件可能不止一个,有很多个,所以要等所有的文件都加载完再执行,所以源码中有一个计数的readyWait。
源码中定义了一个等待栈变量——readyWait,每次执行$.holdReady(true)都会增加压栈,而每次$.holdReady()执行都会弹栈,等空栈的时候就执行jQuery.ready函数,即将promise给resolve掉。
// Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1,//第二步看这里 //holdReady推迟DOM的触发 // Hold (or release) the ready event holdReady: function( hold ) {if ( hold ) {jQuery.readyWait++;//hold为真,让readyWait加加处理} else {jQuery.ready( true );} },// Handle when the DOM is ready ready: function( wait ) { //参数和holdReady有关// Abort if there are pending holds or we're already ready//readyWait为0时就不用hold了,执行后面的操作if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { return;}// Remember that the DOM is readyjQuery.isReady = true; //默认是false// If a normal DOM Ready event fired, decrement, and wait if need beif ( wait !== true && --jQuery.readyWait > 0 ) {return;}//第一步看这里重点,resolveWith改变状态的时候传参了,给done中方法fn传入了参数,//document是fn的this指向,jQuery是参数// If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] );//跟主动触发有关// Trigger any bound ready eventsif ( jQuery.fn.trigger ) {jQuery( document ).trigger("ready").off("ready");} },
刚开始看源码,很多地方理解也不到位,解释可能也不清楚。
参考:
http://www.cnblogs.com/aeexiaoqiang/p/6525702.html
本文作者starof,因知识本身在变化,作者也在不断学习成长,文章内容也不定时更新,为避免误导读者,方便追根溯源,请诸位转载注明出处:http://www.cnblogs.com/starof/p/6856572.html有问题欢迎与我讨论,共同进步。
转载于:https://www.cnblogs.com/starof/p/6856572.html
jquery源码 DOM加载相关推荐
- jQuery源码dom ready分析
一.前言 在平时开发web项目时,我们使用jquery框架时,可能经常这样来使用$(document).ready(fn),$(function(){}),这样使用的原因是在浏览器把DOM树渲染好之前 ...
- jQuery deferred应用dom加载完毕详细源码分析(三)
我承认上章ajax部分写得不好,不要怪我,它的ajax代码太多了,而且跨越大,方法跳跃多,实在不好排版与讲解,但如果你真正想研究源码并且仔细读了得话,你的 收获应该会很大,至少你明白了js的ajax是 ...
- 剖析Spring源码:加载IOC容器
本文接上一篇文章 阅读Spring源码:IOC控制反转前的处理,继续进行下面的分析 首先贴出 Spring bean容器的刷新的核心 11个步骤进行祭拜(一定要让我学会了-阿门) // 完成IoC容器 ...
- Glide源码解析-加载流程
1 引言 一直想要阅读Glide源码,但是苦于时间和功力都不够,总是断断续续的,趁着现在有一些空暇时间,来简要分析Glide的源码.Glide的实现太过复杂,不可能做到面面俱到,如果每一行都细致分析, ...
- jquery中DOM加载事件,onload事件和ready事件
全栈工程师开发手册 (作者:栾鹏) jquery系列教程4-事件操作全解 jquery中DOM加载事件 jquery中的DOM加载事件分为onload事件和ready事件.,具体功能如代码中注释. 代 ...
- jQuery源码解析(3)—— ready加载、queue队列
ready.queue放在一块写,没有特殊的意思,只是相对来说它俩可能源码是最简单的了.ready是在dom加载完成后,以最快速度触发,很实用.queue是队列,比如动画的顺序触发就是通过默认队列'f ...
- echarts asp mysql 源码_如何使用PHP+jQuery+MySQL实现异步加载ECharts地图数据(附源码下载)...
ECharts地图主要用于地理区域数据的可视化,展示不同区域的数据分布信息.ECharts官网提供了中国地图.世界地图等地图数据下载,通过js引入或异步加载json文件的形式调用地图. 本文将结合实例 ...
- jQuery:等页面DOM加载完毕后再执行代码
等着页面DOM加载完毕后再执行代码 第一种方式(比较麻烦,不常用): $(document).ready(function(){ - }) 第二种方式(常用): $(function(){ - }) ...
- jQuery源码研究学习笔记(二)
jQuery总体架构: jQuery模块可以大致分为三部分:入口模块.底层支持模块.功能模块. 参考jQuery技术内幕解析 jquery源码总体架构: (function(window,undefi ...
最新文章
- 在 Google Colab 中使用 OpenCV 进行图像处理简介
- 一个关于在Fedora下安装jdk的问题
- Tomcat6下使用jBPM-4出现 java.lang.LinkageError。javax/el/ExpressionFactory解决办法
- webstorm的安装
- 项目管理(3):备战pmp
- JavaScript类与原型——组织JavaScript代码
- 禁用行、列、单元格单元格编辑
- linux重启网卡命令_如何在 Linux 中更改 MAC 地址 | Linux 中国
- 实践 | 图片文本爬虫与数据分析
- MAC删除自带ABC输入法
- 数码管与74HC573,74HC138电路
- PayPal接口开发
- AVL树(动图详解)
- day01 pathon基础
- U盘中毒文件都不见了
- 基于微信云开发的商家转账至零钱
- 如何使用 LK 字幕脚本工具
- 简单又详细的网页爬虫案例
- 鼠标事件,显示悬浮窗
- 计算机毕设之超市积分管理系统