首页 > 网站 > WEB开发 > 正文

jQuery源码dom ready分析

2024-04-27 14:12:53
字体:
来源:转载
供稿:网友

jQuery源码dom ready分析

  一、前言

  在平时开发web项目时,我们使用jquery框架时,可能经常这样来使用$(document).ready(fn),$(function(){}),这样使用的原因是在浏览器把DOM树渲染好之前,javascript是无法操作没渲染好的DOM节点。

  其实除了$(document).ready(fn),$(function(){})写法外,还有两种让dom渲染完之后执行js的写法:

$(document).on('ready', fn2)  //通过on事件绑定函数,通过trigger触发也可以达到jQuery.ready.PRomise().done(fn); //通过这种方式也可以实现,jQuery.ready.promise()返回一个deferred对象,done(fn)添加回调方法

  其中具体流程图如下(自己简单画了一下,有错请大家指正)

  

二、源码部分(建议看这部分是,先理解清楚deferred,promise)

  ①$(function(){}) =>到rootjQuery.ready(selector);

  我们知道,jQuery是由new jQuery.fn.init(selector, context, rootjQuery)实例出来的,对接了两个参数,selector,context

 // 构造函数,定义一个局部变量的jQuery    jQuery = function (selector, context) {        // jQuery对象实际上是init的构造函数的引用        return new jQuery.fn.init(selector, context, rootjQuery);    }

  当我们使用$(function(){}),则选择器selector参数就变成了funciton,jQuery.fn.init函数判断selector为Funtion时,又指向了rootjQuery.ready(selector),就是$(document).ready(fn);

rootjQuery = $(document)
jQuery.fn = jquery.prototype = {  init:function(selector,context,rootjQuery){    if (jQuery.isFunction(selector)) {        // 引用非静态成员ready方法,等价于$(document).ready(selector)        return rootjQuery.ready(selector);    }  }  } 

  ②$(document).on("ready",fn) =>到jQuery(document).trigger("ready").off("ready");

  要理解$(document).on("ready",fn),我们要看ready部分

    //扩展方法到jquery****************************************    jQuery.extend({        /**        记录监听DOMContentLoaded事件(DOM是否加载完成),加载完成设置为true(类似一个开关)        * type {Boolean} 默认为false,表示页面未加载完。当页面DOM加载完成,设置为true        */        isReady: false,         /**        需要预加载的观察者数量        * type {Number} 观察者数量        */        readyWait: 1,         /**        DOM加载完成,执行预加载        * @param {Boolean} wait 为true表示锁定委托人,为false表示释放委托人        */        ready: function (wait) {             if (wait === true ? --jQuery.readyWait : jQuery.isReady) {                return;            }             // 检测body是否存在(IE的一个bug),存在继续向下执行,不存在进入语句,执行setTimeout定时器,直到body存在            if (!document.body) {                return setTimeout(jQuery.ready);            }              // 开关,记录DOM加载完成            jQuery.isReady = true;             // 检测所有的观察者是否执行完成            if (wait !== true && --jQuery.readyWait > 0) {                return;            }             // 委托人readyList通知观察者,开始执行回调函数,并将document作为这些函数的上下文环境            readyList.resolveWith(document, [jQuery]);             // 检测trigger方法是否存在,触发绑定在document上的事件,执行完成之后并解绑            //    $(document).on('ready', fn2);            //    $(document).ready(fn1);            //这里的fn1会先执行,自己的ready事件绑定的fn2回调后执行            if (jQuery.fn.trigger) {                jQuery(document).trigger("ready").off("ready");            }        }    })    

  ③$(document).ready(fn)

    jQuery.fn = jquery.prototype = {    if (jQuery.isFunction(selector)) {        // 引用非静态成员ready方法        return rootjQuery.ready(selector);    },     ready: function (fn) {                // Add the callback                // promise类似一种事件委托,相当于一个创建委托人(已创建则无需创建,通过readyList判断是否已创建),在DOM加载完成之后,委托人会通知观察者done去执行回调函数fn                //调委托函数,返回deferred对象,添加done(fn)回调函数                jQuery.ready.promise().done(fn);                     return this;            }    }

最后dom ready相关部分源码详细如下:

 // 构造函数,定义一个局部变量的jQuery    jQuery = function (selector, context) {        // jQuery对象实际上是init的构造函数的引用        return new jQuery.fn.init(selector, context, rootjQuery);    }      // 就绪事件处理程序    completed = function (event) {        // document.readyState 判断文档加载状态,'complete'代表文档已经完全加载                if (document.addEventListener || event.type === "load" || document.readyState === "complete") {                    detach(); //清理方法                        jQuery.ready();//执行延迟加载方法        }    }        // 清理DOMContentLoaded事件处理程序,为DOM事件做好准备,触发jQuery.ready方法    detach = function () {        // 标准的W3C监听事件        if (document.addEventListener) {            //删除DOMContentLoaded监听事件            document.removeEventListener("DOMContentLoaded", completed, false);            window.removeEventListener("load", completed, false);        } else {            // 针对IE,非标准的浏览器            // 删除onreadystatechange监听事件            document.detachEvent("onreadystatechange", completed);            window.detachEvent("onload", completed);        }    };        var  readyList,rootjQuery=$(document);    jQuery.fn = jquery.prototype = {    if (jQuery.isFunction(selector)) {        // 引用非静态成员ready方法        return rootjQuery.ready(selector);    },     ready: function (fn) {                // Add the callback                // promise类似一种事件委托,相当于一个创建委托人(已创建则无需创建,通过readyList判断是否已创建),在DOM加载完成之后,委托人会通知观察者done去执行回调函数fn                //调委托函数,返回deferred对象,添加done(fn)回调函数                jQuery.ready.promise().done(fn);                     return this;            }    }            //扩展方法到jquery****************************************    jQuery.extend({        /**        记录监听DOMContentLoaded事件(DOM是否加载完成),加载完成设置为true(类似一个开关)        * type {Boolean} 默认为false,表示页面未加载完。当页面DOM加载完成,设置为true        */        isReady: false,         /**        需要预加载的观察者数量        * type {Number} 观察者数量        */        readyWait: 1,         /**        锁定或释放预加载委托人        * @param {Boolean} hold 为true表示锁定预加载委托人,为false表示释放委托人        */        holdReady: function (hold) {            if (hold) {                jQuery.readyWait++;            } else {                jQuery.ready(true);            }        },         /**        DOM加载完成,执行预加载        * @param {Boolean} wait 为true表示锁定委托人,为false表示释放委托人        */        ready: function (wait) {             // Abort if there are pending holds or we're already ready            if (wait === true ? --jQuery.readyWait : jQuery.isReady) {                return;            }             // 检测body是否存在(IE的一个bug),存在继续向下执行,不存在进入语句,执行setTimeout定时器,直到body存在            if (!document.body) {                return setTimeout(jQuery.ready);            }              // 开关,记录DOM加载完成            jQuery.isReady = true;             // 检测所有的观察者是否执行完成            if (wait !== true && --jQuery.readyWait > 0) {                return;            }             // 委托人readyList通知观察者,开始执行回调函数,并将document作为这些函数的上下文环境            readyList.resolveWith(document, [jQuery]);             // 检测trigger方法是否存在,触发绑定在document上的事件,执行完成之后并解绑            //    $(document).on('ready', fn2);            //    $(document).ready(fn1);            //这里的fn1会先执行,自己的ready事件绑定的fn2回调后执行            if (jQuery.fn.trigger) {                jQuery(document).trigger("ready").off("ready");            }        }    })                        // 预加载委托函数    jQuery.ready.promise = function (obj) {        // 判断预加载委托人是否存在        if (!readyList) {            // 创建一个预加载委托人            readyList = jQuery.Deferred();            /**            W3C标准DOM浏览器            * 0-uninitialized:xml 对象被产生,但没有任何文件被加载。            * 1-loading:加载程序进行中,但文件尚未开始解析。            * 2-loaded:部分的文件已经加载且进行解析,但对象模型尚未生效。            * 3-interactive:仅对已加载的部分文件有效,在此情况下,对象模型是有效但只读的。            * 4-complete:文件已完全加载,代表加载成功。            */            // 检测document内容是否加载完成,加载完成返回true,否者返回false            if (document.readyState === "complete") {                /**                * 函数延迟0毫秒执行并不是立即执行, 而是等浏览器运行完挂起的事件句柄和已经更新完文档状态之后才                * 运行这个函数.详情见《Javascript Definition Guide 5th Edition(JavaScript权威指南第5版)》                * 函数延迟1毫秒或者为空代表立即执行                */                // 立即调用jQuery.ready方法,执行预加载内容                setTimeout(jQuery.ready);                 // 检测是否符合W3C标准事件模型(IE不支持)            } else if (document.addEventListener) {                // 监听DOMContentLoaded事件,当DOM加载完成,触发completed方法                // DOMContentLoaded事件在DOM加载完成时触发                // completed方法,目的是先删除监听DOMContentLoaded事件,然后执行jQuery.ready()方法。(删除事件,清除内存)                document.addEventListener("DOMContentLoaded", completed, false);                 // 若失败,给window.onload注册一个jQuery.ready方法,并在页面加载完成之后执行,目的是兼容低版本浏览器,防止出现预加载失败                window.addEventListener(
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表