jQuery源码 Ajax模块分析

写在前面:

先讲讲ajax中的相关函数,然后结合函数功能来具体分析源代码。

相关函数:

>>ajax全局事件处理程序

.ajaxStart(handler) 注册一个ajaxStart事件处理器。当一个Ajax请求开始,并且同时无其它未完成的Ajax请求时,jQuery触发ajaxStart事件。
.ajaxSend(handler) 注册一个ajaxSend事件处理器。当一个Ajax请求被发送时触发ajaxSend事件。
.ajaxSuccess(handler) 注册一个ajaxSuccess事件处理器。当一个Ajax请求成功时触发ajaxSuccess事件。
.ajaxError(handler) 注册一个ajaxError事件处理器。当一个Ajax请求出错时触发ajaxError事件。
.ajaxComplete(handler) 注册一个ajaxComplete事件处理器。当一个Ajax请求完成时触发ajaxComplete事件。
.ajaxStop(handler) 注册一个ajaxStop事件处理器。,当一个Ajax请求完成,并且同时无其它未完成的Ajax请求时触发ajaxStop事件。

注意:

这六个Ajax全局事件的处理函数都应该注册在document上。

   例如: $(document).ajaxSuccess(handler);

ajax选项中的global是全局ajax事件的开关。如果global选项设置为false,上面的所有ajax全局事件都不会被触发。

特别注意的是ajaxStart和ajaxStop事件上面描述的文字的不同之处。

>> Ajax的基本函数

jQuery.ajaxSetup()

jQuery.ajaxSetup(options) 设置Ajax默认的选项。

options对象包含用来配置ajax请求的key/value键值对。

函数直接扩展了jQuery.ajaxSetting这个对象,这个对象是Ajax请求的默认的配置对象,扩展后对以后的每个Ajax请求都将产生影响。因此非特殊情况不推荐扩展Ajax的默认选项。

Ajax源码中的使用

//扩展jQuery.ajaxSetting默认选项集合
jQuery.ajaxSetup({
    accepts: {
        script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
    },
    contents: {
        script: /(?:java|ecma)script/
    },
    converters: {
        "text script": function( text ) {
            jQuery.globalEval( text );
            return text;
        }
    }
});

上面的代码,扩展了jQuery.ajaxSetting中的三个默认属性,accepts、contents、converters,这三个属性对象添加对script数据类型的支持。后面介绍这三个选项的用途。

jQuery.ajaxPrefilter( )

jQuery.ajaxPrefilter([dataTypes,]handler)

在每个ajax请求开始之前,对请求做前置处理。

dataTypes是包含一个或者多个空格分开的dataType的字符串。 用来限定前置处理应用的Ajax请求的范围。 dataTypes参数可选,默认是”*”,当某个dataType的前置处理函数队列执行完毕后,最终会执行”*”对应的处理函数队列。

handler参数 function(options,originalOptions,jqXHR) 即具体的处理函数,其中options参数代表用户选项集合即originalOptions和默认选项集合即jQuery.ajaxSetting综合后的请求最终使用选项集合,originalOptions代表调用ajax函数时的用户选项集合,jqXHR是jQuery封装的XHR对象,包含相关的属性和方法。

栗子: 在jQuery源码中,Ajax模块有两处使用了这个函数。

// Handle cache‘s special case and global
//script类型请求的前置处理
//a.默认不使用浏览器缓存
//b.对于跨域请求:使用get方法,并且设置global为false,即不触发全局ajax对象。
jQuery.ajaxPrefilter( "script", function( s ) {
    if ( s.cache === undefined ) {
        s.cache = false;
    }
    if ( s.crossDomain ) {
        s.type = "GET";
        s.global = false;
    }
});

// Detect, normalize options and install callbacks for jsonp requests
//对json和jsonp类型ajax请求的前置处理
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
    //省略其它内容...
    
    return "script";
}

注意:

针对某个数据类型dataType,你可以注册多个处理函数。函数会依次执行。

处理函数可以返回一个dataType字符串,此时jQuery不会继续执行队列中的其它后续处理函数,而是将此字符串添加到请求选项的dataTypes头部,并且转而执行此字符串所对应的前置处理程序。

例如上面的代码中,在对json和jsonp的前置处理中,返回”script”,那么script字符串会被添加到options.dataTypes头部(options就是前面提到的请求最终使用的选项集合),并且会跳转到执行”script”对应的前置处理程序。

jQuery.ajaxTransport( )

jQuery.ajaxTransport(dataType,handler)

dataType 表示请求的数据类型。

handler函数,function(options,originalOption,jqXHR) ,函数返回一个对象,这个代表请求此数据类型时,实际使用的完成传输行为的对象。我把它称作传输对象。传输对象应该包含两个方法,send和abort。 jQuery内部会为每个对应此数据类型的Ajax请求创建这个传输对象。

调用过程就像下面这样:

$.ajaxTransport( dataType, function( options, originalOptions, jqXHR ) {
  if( /* transportCanHandleRequest */ ) {
    return {
      send: function( headers, completeCallback ) {
        // Send code
      },
      abort: function() {
        // Abort code
      }
    };
  }
});

其中,send函数的参数

  • headers 对象 包含请求头的各种设置
  • completeCallback 函数 当传输过程完成时,调用此函数来告诉Ajax传输过程结束。
  • completeCallback接受四个参数 ( status, statusText, responses, headers )
  • 其中responses是包含 dataType/value 的对象。例如像这样的{ xml: XMLData, text: textData }

这个函数为ajax请求带来了极大的灵活性,你可以定制自己的传输过程。例如,你可以定制一个dataType为”image”的ajax请求

$.ajaxTransport( "image", function( s ) {
  if ( s.type === "GET" && s.async ) {
    var image;
    return {
      send: function( _ , callback ) {
        image = new Image();
        function done( status ) {
          if ( image ) {
            var statusText = ( status === 200 ) ? "success" : "error",
              tmp = image;
            image = image.onreadystatechange = image.onerror = image.onload = null;
            callback( status, statusText, { image: tmp } );
          }
        }
        image.onreadystatechange = image.onload = function() {
          done( 200 );
        };
        image.onerror = function() {
          done( 404 );
        };
        image.src = s.url;
      },
      abort: function() {
        if ( image ) {
          image = image.onreadystatechange = image.onerror = image.onload = null;
        }
      }
    };
  }
});

注意到上面callback( status, statusText, { image: tmp } ); callback函数的response参数值是{image:tmp}, image对应数据类型。

jQuery的Ajax模块源代码中,有两处调用了ajaxTransport函数。

一种用来生成是Ajax默认的传输对象。

jQuery.ajaxTransport(function( s ) {  
//创建"*"对应的transport,即默认处理所有请求的transport

//代码省略
});

上面的ajaxTransport调用省略了dataType参数,此时创建的就是”*”对应的传输过程,即默认使用的传输过程。

另外一种情况,ajax对于跨域的”script”数据类型的请求,使用特殊的传输对象。

// Bind script tag hack transport
//请求script文件使用的传输对象。
jQuery.ajaxTransport( "script", function(s) {

    // This transport only deals with cross domain requests
    //只处理跨域的script数据类型
    //可以看到跨域的script文件是通过HTML的script标签请求并执行。
    if ( s.crossDomain ) {

        var script,
            head = document.head || jQuery("head")[0] || document.documentElement;

        return {

            send: function( _, callback ) {

                script = document.createElement("script");

                script.async = true;

                if ( s.scriptCharset ) {
                    script.charset = s.scriptCharset;
                }

                script.src = s.url;

                // Attach handlers for all browsers
                //isAbort参数在下面定义的abort方法中手动调用script.onload函数时设为true
                //IE的 script 元素支持onreadystatechange事件,不支持onload事件。
                //FF的script 元素不支持onreadystatechange事件,只支持onload事件。
                script.onload = script.onreadystatechange = function( _, isAbort ) {
                    //isAbort时,做清除script的处理
                    //!script.readyState 说明是在FF下面,此时表明load完成
                    ///loaded|complete/.test( script.readyState )表明在IE下需要检测到readyState为loaded或者complete时,才算load完成
                    if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {

                        // Handle memory leak in IE
                        script.onload = script.onreadystatechange = null;

                        // Remove the script
                        if ( script.parentNode ) {
                            script.parentNode.removeChild( script );
                        }

                        // Dereference the script
                        script = null;

                        // Callback if not abort
                        if ( !isAbort ) {
                            callback( 200, "success" );
                        }
                    }
                };

                // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
                // Use native DOM manipulation to avoid our domManip AJAX trickery
                head.insertBefore( script, head.firstChild );
            },

            abort: function() {
                if ( script ) {
                    script.onload( undefined, true );
                }
            }
        };
    }
});

注意:

与前面讲的ajaxPrefilter相似,每种数据类型可以定义多个传输函数。如果其中一个函数返回了传输对象,那么就终止函数队列的调用。如果具体数据类型未得到传输对象,最后会调用“*”对应的传输函数队列。

jQuery.ajax()

        放在单独的一个篇文章里

>> ajax相关的快捷方法

jQuery.post()

jQuery.get()

jQuery.getJSON()

jQuery.getScript()

.load()

     另起一片文章讲。

>> Ajax源代码的架构和流程分析

    另起一片文章讲。

>>ajax返回jqXHR对象分析,关于Deferred对象

       另起一片文章讲。

 

最后: 第一次写,写文章果然麻烦,感觉内容量好大,一时半会儿写不完,还是分多个板块来写吧。先直接贴Ajax模块的源代码(带注解)。

时间: 2024-11-03 01:37:19

jQuery源码 Ajax模块分析的相关文章

jQuery源码解读-事件分析

最原始的事件注册 addEventListener方法大家应该都很熟悉,它是Html元素注册事件最原始的方法.先看下addEventListener方法签名: element.addEventListener(event, function, useCapture) event:事件名,例如“click”,这里要提醒的一点是不要加前缀“on”;    function:事件触发时执行的函数;    userCapture:默认为false,表示event事件在冒泡阶段触发.如果设置为true,则

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源码分析系列(33) : AJAX中的前置过滤器和请求分发器

jQuery1.5以后,AJAX模块提供了三个新的方法用于管理.扩展AJAX请求,分别是: 1.前置过滤器 jQuery. ajaxPrefilter 2.请求分发器 jQuery. ajaxTransport, 3.类型转换器 ajaxConvert 源码结构: jQuery.extend({ /** * 前置过滤器 * @type {[type]} */ ajaxPrefilter: addToPrefiltersOrTransports(prefilters), /** * 请求分发器 *

jQuery源码分析系列(37) : Ajax 总结

综合前面的分析,我们总结如下3大块: jQuery1.5以后,AJAX模块提供了三个新的方法用于管理.扩展AJAX请求 前置过滤器 jQuery. ajaxPrefilter 请求分发器 jQuery. ajaxTransport 类型转换器 ajaxConvert 为了整体性与扩展性考虑,把整个结构通过Deferred实现异步链式模型,Promise对象可以轻易的绑定成功.失败.进行中三种状态的回调函数,然后通过在状态码在来回调不同的函数就行了 出于同源策略考虑,存在跨域问题,所以ajax内部

jQuery源码分析系列(31) : Ajax deferred实现 - Aaron.

AJAX的底层实现都是浏览器提供的,所以任何基于api上面的框架或者库,都只是说对于功能的灵活与兼容维护性做出最优的扩展 ajax请求的流程: 1.通过 new XMLHttpRequest 或其它的形式(指IE)生成ajax的对象xhr. 2.通过xhr.open(type, url, async, username, password)的形式建立一个连接. 3.通过setRequestHeader设定xhr的请求头部(request header). 4.通过send(data)请求服务器端

jQuery源码分析系列(36) : Ajax - 类型转化器

什么是类型转化器? jQuery支持不同格式的数据返回形式,比如dataType为 xml, json,jsonp,script, or html 但是浏览器的XMLHttpRequest对象对数据的响应只有 responseText与responseXML 二种 所以现在我要定义dataType为jsonp,那么所得的最终数据是一个json的键值对,所以jQuery内部就会默认帮你完成这个转化工作 jQuery为了处理这种执行后数据的转化,就引入了类型转化器,如果没有指定类型就依据响应头Con

jQuery源码分析系列(34) : Ajax - 预处理jsonp

上一章大概讲了前置过滤器和请求分发器的作用,这一章主要是具体分析每种对应的处理方式 $.ajax()调用不同类型的响应,被传递到成功处理函数之前,会经过不同种类的预处理(prefilters). 预处理的类型取决于由更加接近默认的Content-Type响应,但可以明确使用dataType选项进行设置.如果提供了dataType选项, 响应的Content-Type头信息将被忽略. 有效的数据类型是text, html, xml, json,jsonp,和 script. dataType:预期

jQuery源码分析系列(35) : Ajax - jsonp的实现与原理

ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本 json核心就是:允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了. jquery ext dojo这类库的实现手段其实大同小异 在同源策略下,在某个服务器下的页面是无法获取到该服务器以外的数据的,但img.iframe.s

jQuery源码分析系列(38) : 队列操作

Queue队列,如同data数据缓存与Deferred异步模型一样,都是jQuery库的内部实现的基础设施 Queue队列是animate动画依赖的基础设施,整个jQuery中队列仅供给动画使用 Queue队列 队列是一种特殊的线性表,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队).队列的特点是先进先出(FIFO-first in first out),即最先插入的元素最先被删除. 为什么要引入队列? 我们知道代码的执行流有异步与同步之分,例如 var a