• 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模块的源代码(带注解)。

  • 相关阅读:
    hadoop shell 命令
    java正则提取括号中的关键词
    java使用ac算法实现关键词高亮
    mysql事务级别和spring中应用
    elasticsearch java工具类
    【记录】研究生周练题目清单
    【记录】研究生已阅文献清单
    论文阅读(11)RoBERTa: A Robustly Optimized BERT Pretraining Approach(2019)
    论文阅读(10)Shallow Convolutional Neural Network for Implicit Discourse Relation Recognition
    论文阅读(9)Towards Cross-Domain PDTB-Style Discourse Parsing(2014)
  • 原文地址:https://www.cnblogs.com/cheerfulCoder/p/4047456.html
Copyright © 2020-2023  润新知