JQuery源码解析-Dom加载过程

下面的几个工具方法都是和dom加载有关,所以先从dom加载开始。

用到的方法:

  isReady:DOM是否已经加载完(内部使用)

  readyWait():等待多少文件的计时器(内部使用)

  holdReady()::推迟DOM触发

  ready():准备DOM触发

  jQuery.ready.promise = function( obj ) {}检测dom的异步操作

先看一下jQuery和原生js加载方式有什么不同:

     $(function () {
        });
        window.onload = function () {
        };

jQuery是等待页面中所有的dom加载完毕,而原生JavaScript的onload方法,则是等待页面所有的元素加载完毕,

例如:一个img标签,jQuery只等这个img标签加载完毕,不必等到src中所引用的图片加载完毕,但onload方法,则必须等到src中的图片加载完毕才可以。

下面看一下jQuery的加载流程图:

前面已经说过  $(function () {})和rootjQuery.ready( selector )是相等的,也就是说$(function () {})这种形式写法,其实最后也被转换成rootjQuery.ready( selector )。

而rootjQuery.ready( selector )这个实例方法里:

ready: function( fn ) {
        // Add the callback
        jQuery.ready.promise().done( fn );

        return this;
    },

又是调用的工具方法中的jQuery.ready.promise().done( fn ),所以先从这个方法开始分析,代码如下:

jQuery.ready.promise = function( obj ) {
    if ( !readyList ) {

        readyList = jQuery.Deferred();

        // Catch cases where $(document).ready() is called after the browser event has already occurred.
        // we once tried to use readyState "interactive" here, but it caused issues like the one
        // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
        if ( document.readyState === "complete" ) {
            // Handle it asynchronously to allow scripts the opportunity to delay ready
            setTimeout( jQuery.ready );

        } else {

            // Use the handy event callback
            document.addEventListener( "DOMContentLoaded", completed, false );

            // A fallback to window.onload, that will always work
            window.addEventListener( "load", completed, false );
        }
    }
    return readyList.promise( obj );
};

这个方法中有判断:

首先判断如果document.readyState === "complete" ,那么已经代表了在运行到这时,页面中的dom已经加载完毕了,然后运行setTimeout( jQuery.ready )

这里用到了setTimeout方法,是为了兼容ie的hack方法,具体原因可以看一下注释中的网址。

如果readyState 不等于complete,那么就会添加两个回调方法,这里添加两个的原因,是因为在火狐等浏览器中,会缓存load方法,所以就会先调用load方法,所以这里添加了两个回调,保证了在第一时间内调用complete方法。

下面在看一下complete方法中写了什么:

// The ready event handler and self cleanup method
    completed = function() {
        document.removeEventListener( "DOMContentLoaded", completed, false );
        window.removeEventListener( "load", completed, false );
        jQuery.ready();
    };

通过源码可以看到,这里无论哪种方法进行了回调,都会在这里将事件解绑,所以这里也就保证了只回调一次,最后又调用了jQuery.ready()方法。

这也说明,其实在jQuery.ready.promise方法中,无论条件如何,都会调用jQuery.ready()方法。

在说ready()方法前,先来说明一下holdReady方法。

这个方法是阻塞dom加载的,看一下这个例子:

a.js:

alert(1);

调用页面:

$.getScript("a.js", function () {
        })
 $(function () {
  alert(2);});

这时运行,查看结果发现,其实先弹出的是2,然后才是1,这显然和我们的预期不一致,一般我们在页面中引用js的时候,都是想使用这个js文件,然后在进行下面的操作。

但因为是异步,所以当前的结果表明,是最后才运行了a.js中的内容。

所以这时就用到了holdReady方法:

            $.holdReady(true);

            $.getScript("a.js", function () {
                 $.holdReady(false)
            })
            $(function () {

                alert(2);
            });

这时页面的运行结果就正确了。

源码:

// 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,

    // Hold (or release) the ready event
    holdReady: function( hold ) {
        if ( hold ) {
            jQuery.readyWait++;
        } else {
            jQuery.ready( true );
        }
    },

可以看到,方法内部有个计数器,这也就说明了,当页面加载多个js文件时,可以进行多次调用,保证所有文件都加载完毕,才可以继续运行。

如果传入的参数为false,则执行ready方法,并传入true:

ready: function( wait ) {

        // Abort if there are pending holds or we‘re already ready
        if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
            return;
        }

        // Remember that the DOM is ready
        jQuery.isReady = true;

        // 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.resolveWith( document, [ jQuery ] );

        // Trigger any bound ready events
        if ( jQuery.fn.trigger ) {
            jQuery( document ).trigger("ready").off("ready");
        }
    },

第一个判断,如果为true,则将计数器减一,否则判断isReady变量

第二个判断,如果计数器还大于0的话,则继续等待。

到readyList.resolveWith( document, [ jQuery ] ); 这句代码,就开始运行延时的方法了,第一个参数指定节点,第二个是将jQuery传入

可以通过下面的代码查看:

 $(function (arg) {
                console.log(this);
                console.log(arg);
            })

运行结果可以看到 this:document arg:jQuery对象。

下面看最后一段代码

        // Trigger any bound ready events
        if ( jQuery.fn.trigger ) {
            jQuery( document ).trigger("ready").off("ready");
        }

这段代码是考虑到另一种加载方式:

 $(document).on(‘ready‘, function () {
                alert(1);
            })

如果将这段代码注释,可以看到,这种方式就无法运行了。

所以这也说明了,jQuery其实有三种写法:

         $(function () {})
            $(document).ready(function () { })
            $(document).on(‘ready‘, function () {})
时间: 2024-08-06 03:16:10

JQuery源码解析-Dom加载过程的相关文章

SSH 之 Spring的源码(一)——Bean加载过程

看看Spring的源码,看看巨人的底层实现,拓展思路,为了更好的理解原理,看看源码,深入浅出吧.本文基于Spring 4.0.8版本. 首先Web项目使用Spring是通过在web.xml里面配置 org.springframework.web.context.ContextLoaderListener初始化IOC容器的 <span style="font-family:SimSun;font-size:18px;"><listener> <listene

jQuery源码解析(架构与依赖模块)第一章 理解架构

1-1 jQuery设计理念 引用百科的介绍: jQuery是继prototype之后又一个优秀的Javascript框架.它是轻量级的js库 ,它兼容CSS3,还兼容各种浏览器(IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+),jQuery2.0及后续版本将不再支持IE6/7/8浏览器.jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用).events.实现动画效果,并且方便地为网站提供AJAX交互.jQuery还有一个比较大的优势是,它

二.jQuery源码解析之构建jQuery之构建函数jQuery的7种用法

一:$(selectorStr[,限制范围]),接受一个选择器(符合jQuery规范的字符串),返回一个jQuery对象;二:$(htmlStr[,文档对象]),$(html[,json对象])传入html字符串,创建一个新的dom元素 三:$(dom元素),$(dom元素集合)将dom元素转换成jQuery对象.四:$(自定义对象)封装普通对象为jQuery对象.五:$(回调函数)绑定ready事件监听函数,当Dom加载完成时执行.六:$(jQuery对象)接受一个jQuery对象,返回一个j

jquery源码解析:jQuery工具方法详解1

jQuery的工具方法,其实就是静态方法,源码里面就是通过extend方法,把这些工具方法添加给jQuery构造函数的. jQuery.extend({       //当只有一个对象时,就把这个对象中的属性和方法扩展到this对象中,这里的this指向jQuery expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), //唯一性,core_version 为jQuery

Prism 源码解读3-Modules加载

原文:Prism 源码解读3-Modules加载 目录 介绍 0.Modules加载 1.通过AppSetting加载 2.通过代码加载 3.通过目录加载 4.通过手动方式加载 总结 回到顶部 介绍 在软件开发过程中,总想组件式的开发方式,各个组件之间最好互不影响,独立测试.Prism的Modules很好的满足了这一点. 这个架构图很好了讲解了Prism的Modules的概念 Prism支持通过配置文件,文件夹,手动载入Module的方式,并且对Module的载入进行验证,包括重复和循环依赖验证

八.jQuery源码解析之get()

理论上get是用来返回jQuery对象中部分或全部元素为数组的,但是转换为数组后,数组中的单个元素又是一个一个dom元素.所以get还有另外一个功效,就是将jQuery对象转换成dom对象.如果get中的参数为空了,则直接调用toArray();如果参数小于0,则表示从元素后面开始计算,如果num>0表示直接返回指定位置的元素. 八.jQuery源码解析之get(),布布扣,bubuko.com

jquery源码解析:代码结构分析

本系列是针对jquery2.0.3版本进行的讲解.此版本不支持IE8及以下版本. (function(){ (21, 94)     定义了一些变量和函数,   jQuery = function(){}; (96,283)   给jQuery对象添加一些属性和方法(实例方法,通过$("div")这类的jQuery实例对象来调用) (285,347)   extend : jQuery的继承方法 (349,817)   jQuery.extend():扩展一些工具方法(静态方法,直接通

十七.jQuery源码解析之入口方法Sizzle(1)

函数Sizzle(selector,context,results,seed)用于查找与选择器表达式selector匹配的元素集合.该函数是选择器引擎的入口. 函数Sizzle执行的6个关键步骤如下: 1.解析选择器表达式,解析出块表达式和关系符. 2.如果存在位置伪类,则从左向右查找: a.查找第一个块表达式匹配的元素集合,得到第一个上下文元素集合. b.遍历剩余的块表达式和块间关系符,不断缩小上下文元素集合. 3.否则从右向左查找: a.查找最后一个块表达式匹配的元素集合,得到候选集,映射集

十六.jQuery源码解析之Sizzle设计思路.htm

为了便于后面的叙述,需要了解一些相关术语和约定. 并列选择器表达式:"div,p,a"====>div,p,a是并列的. 块表达式:"div>p"中的div和p就是两个块. 块表达式的类型:共8种.id,class,name,attr,tag,child,pos,pseudo(伪类表达式) 块间的关系符:共4种.">":父子关系,"+":紧挨着的兄弟关系,"~":后面的所有兄弟关系,&qu