对象方法jQuery ajax —— 主函数分析

PS:今天上午,非常郁闷,有很多简略基础的问题搞得我有些迷茫,哎,码代几天不写就忘。目前又不当COO,还是得用心记码代哦!

    由于jQuery ajax对Callbacks、Deferred、serialize、event等模块的赖依,议建对这些模块没有识认的友朋看一下jQuery CallbacksjQuery DeferredjQuery serializejQuery event(上)jQuery event(下)

    这篇文章重要分析的是具有380+行的jQuery.ajax数函,该数函是jQuery ajax的心核数函,jQuery的其他ajax方法几乎都是基于该方法的。

    上一篇文章我们了解了Baidu ajax(当然是旧版的,还是被简化的……),那么我们想给这个简略的ajax方法加添什么功能呢?

 

    

可链式操纵

    既然是jQuery必定先要决解的是链式操纵的问题。

    jQuery中的Deferred可以实现异步链式模型实现,Promise对象可以易轻的定绑胜利、失败、行进中三种状态的回调数函,然后通过在状态码在来回调不同的数函就好了。

 

    

但仅仅回返一个promise没什么用

    promise只能处置异步,我们须要回返一个更有效的货色。

    jqXHR就是这样的货色,实际上他是一个寨山版的XHR对象。

    这样我们就可以展扩一下XHR对象的功能, 供提定一的容错处置,露暴给外部供提一些方法。

// 假货xhr,或者说寨山xhr……╮(╯▽╰)╭
// 为了可以实现链式操纵
// 便顺展扩一下xhr对象功能
// 还有供提定一的容错处置
jqXHR = {
    // 预备状态
    readyState: 0,

    // 如果须要,建创一个响应头参数的表
    getResponseHeader: function( key ) {
        var match;
        // 如果状态为2,状态2示表ajax成完
        if ( state === 2 ) {
            // 如果没有响应头
            if ( !responseHeaders ) {
                // 响应头设空
                responseHeaders = {};
                while ( (match = rheaders.exec( responseHeadersString )) ) {
                    // 组装响应头
                    responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
                }
            }
            // 响应头对应的key的值
            match = responseHeaders[ key.toLowerCase() ];
        }
        // 回返
        return match == null ? null : match;
    },

    // 回返响应头字符串
    getAllResponseHeaders: function() {
        // 看看否是接收到了,接收到直接回返,否则为null
        return state === 2 ? responseHeadersString : null;
    },

    // 设置请求头
    setRequestHeader: function( name, value ) {
        var lname = name.toLowerCase();
        // 如果state不为0
        if ( !state ) {
            // 如果requestHeadersNames[ lname ]不为空,
            // 则requestHeadersNames[ lname ]稳定,name设置为该值
            // 否则,requestHeadersNames[ lname ]不空,
            // 则requestHeadersNames[ lname ]设置为name,
            // 该射映关系用于免避户用巨细写书写错误之类的问题,容错处置
            name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
            // 在现的name是对的,或者是第一次设置这个name,不须要容错
            // 设置请求头对应值
            requestHeaders[ name ] = value;
        }
        return this;
    },

    // 重写响应头content-type
    overrideMimeType: function( type ) {
        if ( !state ) {
            s.mimeType = type;
        }
        return this;
    },

    // 对应状态的回调数函集
    statusCode: function( map ) {
        var code;
        // 如果map存在,预备组装
        if ( map ) {
            // 如果状态小于2,示表旧的回调可能还没有效到
            if ( state < 2 ) {
                // 历遍map面里的有所code
                for ( code in map ) {
                    // 用似类链表的方法加添,以证保旧的回调仍然存在
                    statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
                }
            // 状态大于2,证明经已成完了
            } else {
                // 无论Deferred胜利还是失败都执行前当状态回调
                jqXHR.always( map[ jqXHR.status ] );
            }
        }
        return this;
    },

    // 中断请求
    abort: function( statusText ) {
        var finalText = statusText || strAbort;
        // 可以先懂得成XHR对象,当然这也不是真正的XHR对象
        if ( transport ) {
            transport.abort( finalText );
        }
        // 调用done,示表干完了
        done( 0, finalText );
        return this;
    }
};
 

    

可是这还没有链式啊!

    

    怎么把jqXHR成变一个Promise呢?

    

    让一个对象具有另一个对象的方法,大家会想到什么呢?

    承继?

    不,直接插上去就好了……这里就现体了Javascript“易插拔”的点特……自己乱起的……囧rz……

    应该说动态、弱类的点特。

    什么意思?就是将Promise上的方法插到jqXHR对象上就好了。

    // 在jqXHR粘上promise的有所方法,此时jqXHR就很像一个promise了
    // 实际上就是用jQuery.extend(jqXHR, promise)而已
    // jqXHR刚寨山了xhr对象,又开始寨山promise对象了
    // 便顺把jqXHR的complete绑上completeDeferred.add
    // 意思是jqXHR状态成完后调用completeDeferred这个Callbacks排队
    // 话说promise面里并没有complete这个方法
    // 面后我们可以看到,作者大人又要给jqXHR插上complete、success、error方法
    // Javascript就是这样简略,即插即用……囧rz
    deferred.promise( jqXHR ).complete = completeDeferred.add;
    // 定绑jqXHR.success为promise面里的done方法
    jqXHR.success = jqXHR.done;
    // 定绑jqXHR.error为promise面里的fail方法
    jqXHR.error = jqXHR.fail;

    这模样直接插上去在强类语言中是做不到的,当然也可以用组合模式来实现一个对象具有多个对象的方法,但是却没法动态的去给对象加添各种方法。

    强类语言会制约对象子辈一只能“会”那么几种“方法”,Javascript的对象可以在生命周期内意随“习学”各种“方法”。

    所以说,强类语言和Javascript的对象模型是有差异的,将设计模式套硬搬生进Javascript或许是错误的。

    我们再举个例子,比如如果用所谓的Javascript组合模式来重写面上的码代可能会是这样的:

// 义定局部变量deferred和completeDeferred
function JQXHR(){
    // 义定jqXHR的属性和方法
    for(i in deferred.promise){
        this[i] = this.promise[i];
    }
    this.complete = completeDeferred.add;
    this.success = this.done;
    this.error = this.done
}

var jqXHR = new JQXHR();
大家认为哪个好呢?

    成变面上的模样重要是因为要决解上面两个问题:

    

  1. jqXHR由于是露暴在外的,他不能包括deferred和completeDeferred,不许允户用在外部操纵这两个对象的状态。
  2. deferred和completeDeferred也不能成为jqXHR的私有变量,因为还要更具ajax事件发触。

    

 

    

供提全局事件,使得UI可以根据ajax状态行进转变

    这里重要利用了jQuery.event.trigger和jQuery.fn.trigger模拟发事件。

    // 如果须要,而且全局事件没有被发触过
    if ( fireGlobals && jQuery.active++ === 0 ) {
        // 则通过jQuery.event.trigger模拟发触
        jQuery.event.trigger("ajaxStart");
    }

    当ajax开始时模拟全局事件,ajaxStart。

    

        // 如果须要,对特定对象发触全局事件ajaxSend
        if ( fireGlobals ) {
            globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
        }

    ajax发送消息,发触ajaxSend。

    

        // 如果须要发触全局事件
        if ( fireGlobals ) {
            // 对指定元素发触事件ajaxSuccess或者ajaxError
            globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
                [ jqXHR, s, isSuccess ? success : error ] );
        }

        // 回调成完后的Callbacks队列
        completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );

        // 如果须要发触全局事件
        if ( fireGlobals ) {
            // 对指定元素发触事件ajaxComplete
            globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
            // 该ajax发触终了,标记active减1,如果为0,证明有所ajax束结
            if ( !( --jQuery.active ) ) {
                // 发触ajaxStop事件
                jQuery.event.trigger("ajaxStop");
            }
        }    

    束结时候发触ajaxSuccess或ajaxError,再发出ajaxComplete,如果全体ajax束结则发触ajaxStop。

    

 

 

    

否是许允应用存缓数据

    // 如果不须要content
    // 看看需不须要加其他信息
    if ( !s.hasContent ) {

        // 如果data存在,那么经已序列化
        if ( s.data ) {
            // 加添到cacheURL中
            cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
            // 删除掉则面后就不会被发送出去了
            delete s.data;
        }

        // 看看否是须要免避数据从存缓中读取
        if ( s.cache === false ) {
        
            s.url = rts.test( cacheURL ) ?

                // 如果经已有_参数,那么设置他的值
                cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :

                // 否则加添一个_ = xxx在URL面后
                cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
        }
    }

    通过给地址附加参数_=xxx来免避存缓。

    

    // 看看需不须要设置If-Modified-Since和If-None-Match头信息
    if ( s.ifModified ) {
        if ( jQuery.lastModified[ cacheURL ] ) {
            jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
        }
        if ( jQuery.etag[ cacheURL ] ) {
            jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
        }
    }

    以及设置If-Modified-Since和If-None-Match头信息。

    

    // 看看否是须要存缓置If-Modified-Since和If-None-Match头
    if ( s.ifModified ) {
        // 取得Last-Modified
        modified = jqXHR.getResponseHeader("Last-Modified");
        // 如果Last-Modified存在
        if ( modified ) {
            // 在jQuery.lastModified[cacheURL]保存Last-Modified
            jQuery.lastModified[ cacheURL ] = modified;
        }
        // 取得etag
        modified = jqXHR.getResponseHeader("etag");
        // 如果etag存在
        if ( modified ) {
            // 在jQuery.etag[cacheURL]存缓etag
            jQuery.etag[ cacheURL ] = modified;
        }
    }

    存缓If-Modified-Since和If-None-Match头信息。

    

 

    

设置超时

        // 如果是异步,并且设置了超时
        if ( s.async && s.timeout > 0 ) {
            // 设置超时
            timeoutTimer = setTimeout(function() {
                jqXHR.abort("timeout");
            }, s.timeout );
        }

    重要功能分析完了,完整备注码代见下。 

    

 

    

完整备注

    每日一道理
有一首诗最为动人,那就是青春;有一段人生最美丽,那就是青春;有一道风景最为亮丽,那就是青春。青春,不要说已疲惫,也许你的幻想曾被现实无情毁灭,也许你的追求毫无结果,但你应该相信,没有寒风的洗礼,哪来万紫千红的春天,没有心的耕耘,哪有累累硕果?
jQuery.ajax = function( url, options ) {

    // 如果url是一个obj,模拟1.5版本以前的方法
    if ( typeof url === "object" ) {
        options = url;
        url = undefined;
    }

    // 设置options
    options = options || {};

    var transport,
        // 存缓cacheURL
        cacheURL,
        // 响应头
        responseHeadersString,
        responseHeaders,
        // 超时控制器
        timeoutTimer,
        // 跨域判定变量
        parts,
        // 否是须要发触全局事件
        fireGlobals,
        // 循环变量
        i,
        // 通过jQuery.ajaxSetup改造参数对象
        s = jQuery.ajaxSetup( {}, options ),
        // 回调指定上下文,也就是他的this
        callbackContext = s.context || s,
        // 全局事件中的响应数函的指定上下文
        // 有s.context,且是DOM节点,或者jQuery收集器
        globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
            // 通过jQuery包装
            jQuery( callbackContext ) :
            // 否则为jQuery.event
            jQuery.event,
        // 新建一个deferred
        deferred = jQuery.Deferred(),
        // deferred成完后的Callbacks队列
        completeDeferred = jQuery.Callbacks("once memory"),
        // 对应状态的回调数函集
        statusCode = s.statusCode || {},
        // 请求头
        requestHeaders = {},
        requestHeadersNames = {},
        // 包装类jqXHR的状态
        state = 0,
        // 默认中断消息
        strAbort = "canceled",
        // 假货xhr,或者说寨山xhr……╮(╯▽╰)╭
        // 为了可以实现链式操纵
        // 便顺展扩一下xhr对象功能
        // 还有供提定一的容错处置
        jqXHR = {
            // 预备状态
            readyState: 0,

            // 如果须要,建创一个响应头参数的表
            getResponseHeader: function( key ) {
                var match;
                // 如果状态为2,状态2示表ajax成完
                if ( state === 2 ) {
                    // 如果没有响应头
                    if ( !responseHeaders ) {
                        // 响应头设空
                        responseHeaders = {};
                        while ( (match = rheaders.exec( responseHeadersString )) ) {
                            // 组装响应头
                            responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
                        }
                    }
                    // 响应头对应的key的值
                    match = responseHeaders[ key.toLowerCase() ];
                }
                // 回返
                return match == null ? null : match;
            },

            // 回返响应头字符串
            getAllResponseHeaders: function() {
                // 看看否是接收到了,接收到直接回返,否则为null
                return state === 2 ? responseHeadersString : null;
            },

            // 存缓请求头
            setRequestHeader: function( name, value ) {
                var lname = name.toLowerCase();
                // 如果state不为0
                if ( !state ) {
                    // 如果requestHeadersNames[ lname ]不为空,
                    // 则requestHeadersNames[ lname ]稳定,name设置为该值
                    // 否则,requestHeadersNames[ lname ]不空,
                    // 则requestHeadersNames[ lname ]设置为name,
                    // 该射映关系用于免避户用巨细写书写错误之类的问题,容错处置
                    name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
                    // 在现的name是对的,或者是第一次设置这个name,不须要容错
                    // 设置请求头对应值
                    requestHeaders[ name ] = value;
                }
                return this;
            },

            // 重写响应头content-type
            overrideMimeType: function( type ) {
                if ( !state ) {
                    s.mimeType = type;
                }
                return this;
            },

            // 对应状态的回调数函集
            statusCode: function( map ) {
                var code;
                // 如果map存在,预备组装
                if ( map ) {
                    // 如果状态小于2,示表旧的回调可能还没有效到
                    if ( state < 2 ) {
                        // 历遍map面里的有所code
                        for ( code in map ) {
                            // 用似类链表的方法加添,以证保旧的回调仍然存在
                            statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
                        }
                    // 状态大于2,证明经已成完了
                    } else {
                        // 无论Deferred胜利还是失败都执行前当状态回调
                        jqXHR.always( map[ jqXHR.status ] );
                    }
                }
                return this;
            },

            // 中断请求
            abort: function( statusText ) {
                var finalText = statusText || strAbort;
                // 可以先懂得成XHR对象,当然这也不是真正的XHR对象
                if ( transport ) {
                    transport.abort( finalText );
                }
                // 调用done,示表干完了
                done( 0, finalText );
                return this;
            }
        };

    // 在jqXHR粘上promise的有所方法,此时jqXHR就很像一个promise了
    // 实际上就是用jQuery.extend(jqXHR, promise)而已
    // jqXHR刚寨山了xhr对象,又开始寨山promise对象了
    // 便顺把jqXHR的complete绑上completeDeferred.add
    // 意思是jqXHR状态成完后调用completeDeferred这个Callbacks排队
    // 话说promise面里并没有complete这个方法
    // 面后我们可以看到,作者大人又要给jqXHR插上complete、success、error方法
    // Javascript就是这样简略,即插即用……囧rz
    deferred.promise( jqXHR ).complete = completeDeferred.add;
    // 定绑jqXHR.success为promise面里的done方法
    jqXHR.success = jqXHR.done;
    // 定绑jqXHR.error为promise面里的fail方法
    jqXHR.error = jqXHR.fail;

    // 确定url参数,否则用前当地址。将地址的#号面后的有所货色去掉
    // 比如http://127.0.0.1#main,去掉这个#main
    // 如果开头是//,及数据传输协议没有,那么用前当页面的数据传输协议替换
    // 比如//127.0.0.1,成变http://127.0.0.1
    s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );

    // 义定type,向后兼容
    s.type = options.method || options.type || s.method || s.type;

    // 取出数据类型列表
    // 没有则为"*",
    // 有则认为是用空格分隔的字符串,将其成变数组
    s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];

    // 当协议、主机、端口和前当不匹配时,证明这是一个跨域请求
    if ( s.crossDomain == null ) {
        // 分隔前当url
        parts = rurl.exec( s.url.toLowerCase() );
        // 判定否是是跨域
        s.crossDomain = !!( parts &&
            ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
                ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
                    ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
        );
    }

    // 如果data经已是一个字符串了,那么就不用转换了
    if ( s.data && s.processData && typeof s.data !== "string" ) {
        // 序列化
        s.data = jQuery.param( s.data, s.traditional );
    }

    // 预过滤
    inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );

    // 如果请求被prefilter终止,则退出
    if ( state === 2 ) {
        return jqXHR;
    }

    // 看看需不须要发触全局事件
    fireGlobals = s.global;

    // 如果须要,而且全局事件没有被发触过
    if ( fireGlobals && jQuery.active++ === 0 ) {
        // 则通过jQuery.event.trigger模拟发触
        jQuery.event.trigger("ajaxStart");
    }

    // 将类型大写
    s.type = s.type.toUpperCase();

    // 判断需不须要设置content
    s.hasContent = !rnoContent.test( s.type );

    // 存缓URL,用来在之后设置If-Modified-Since和If-None-Match
    cacheURL = s.url;

    // 如果不须要content
    // 看看需不须要加其他信息
    if ( !s.hasContent ) {

        // 如果data存在,那么经已序列化
        if ( s.data ) {
            // 加添到cacheURL中
            cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
            // 删除掉则面后就不会被发送出去了
            delete s.data;
        }

        // 看看否是须要免避数据从存缓中读取
        if ( s.cache === false ) {
        
            s.url = rts.test( cacheURL ) ?

                // 如果经已有_参数,那么设置他的值
                cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :

                // 否则加添一个_ = xxx在URL面后
                cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
        }
    }

    // 看看需不须要设置If-Modified-Since和If-None-Match头信息
    if ( s.ifModified ) {
        if ( jQuery.lastModified[ cacheURL ] ) {
            jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
        }
        if ( jQuery.etag[ cacheURL ] ) {
            jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
        }
    }

    // 如果数据须要被发送,设置正确的头
    if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
        jqXHR.setRequestHeader( "Content-Type", s.contentType );
    }

    // 根据dataType,设置一个Accept头
    jqXHR.setRequestHeader(
        "Accept",
        s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
            s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
            s.accepts[ "*" ]
    };

    // 历遍s.headers,将其内参数设置入请求头
    for ( i in s.headers ) {
        jqXHR.setRequestHeader( i, s.headers[ i ] );
    }

    // 通过beforeSend检查否是须要发送
    if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
        // 终止
        return jqXHR.abort();
    }

    // 此时abort数函不是取消ajax,而是中断了ajax
    strAbort = "abort";

    // 在jqXHR上定绑胜利、错误、成完回调数函
    for ( i in { success: 1, error: 1, complete: 1 } ) {
        jqXHR[ i ]( s[ i ] );
    }

    // 得到transport
    transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );

    // 如果没有,自动终止
    if ( !transport ) {
        done( -1, "No Transport" );
    } else {
        // 否则,设置reayState为1
        jqXHR.readyState = 1;
        
        // 如果须要,对特定对象发触全局事件ajaxSend
        if ( fireGlobals ) {
            globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
        }
        // 如果是异步,并且设置了超时
        if ( s.async && s.timeout > 0 ) {
            // 设置超时
            timeoutTimer = setTimeout(function() {
                jqXHR.abort("timeout");
            }, s.timeout );
        }

        try {
            // 设置state为1
            state = 1;
            // 开始发送
            transport.send( requestHeaders, done );
        } catch ( e ) {
            // 截获错误,如果ajax未成完
            if ( state < 2 ) {
                done( -1, e );
            // 成完了就直接抛出错误
            } else {
                throw e;
            }
        }
    }

    // 成完时的回调数函
    function done( status, nativeStatusText, responses, headers ) {
        var isSuccess, success, error, response, modified,
            statusText = nativeStatusText;

        // 如果经已调用过该数函,直接退出
        if ( state === 2 ) {
            return;
        }

        // 设置在现状态已成完
        state = 2;

        // 清除超时设置
        if ( timeoutTimer ) {
            clearTimeout( timeoutTimer );
        }
        // 不管jqXHR对象要被用到何时,
        // 释放transport的引用使得他可以先被垃圾回收
        transport = undefined;

        // 存缓响应头
        responseHeadersString = headers || "";

        // 设置readyState
        jqXHR.readyState = status > 0 ? 4 : 0;

        // 得到响应数据
        if ( responses ) {
            // 通过ajaxHandleResponses处置数据
            response = ajaxHandleResponses( s, jqXHR, responses );
        }

        // If successful, handle type chaining
        // 如果胜利
        if ( status >= 200 && status < 300 || status === 304 ) {

            // 看看否是须要存缓If-Modified-Since和If-None-Match头
            if ( s.ifModified ) {
                // 取得Last-Modified
                modified = jqXHR.getResponseHeader("Last-Modified");
                // 如果Last-Modified存在
                if ( modified ) {
                    // 在jQuery.lastModified[cacheURL]保存Last-Modified
                    jQuery.lastModified[ cacheURL ] = modified;
                }
                // 取得etag
                modified = jqXHR.getResponseHeader("etag");
                // 如果etag存在
                if ( modified ) {
                    // 在jQuery.etag[cacheURL]存缓etag
                    jQuery.etag[ cacheURL ] = modified;
                }
            }

            // 如果没有修改
            if ( status === 304 ) {
                // 设置胜利
                isSuccess = true;
                // 设置状态为notmodified
                statusText = "notmodified";

            // 否则得到必要的数据
            } else {
                isSuccess = ajaxConvert( s, response );
                statusText = isSuccess.state;
                success = isSuccess.data;
                error = isSuccess.error;
                isSuccess = !error;
            }
        // 如果失败
        } else {
            // 从statusText获取error状态
            // 在设置statusText成"error"
            // 并转变status为0
            error = statusText;
            if ( status || !statusText ) {
                statusText = "error";
                if ( status < 0 ) {
                    status = 0;
                }
            }
        }

        // 开始设置寨山xhr对象jqXHR的status和statusText
        jqXHR.status = status;
        jqXHR.statusText = ( nativeStatusText || statusText ) + "";

        // 根据胜利还是失败,对deferred行进回调
        if ( isSuccess ) {
            deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );    
        } else {
            deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
        }

        // 根据目前statusCode回调
        jqXHR.statusCode( statusCode );
        statusCode = undefined;

        // 如果须要发触全局事件
        if ( fireGlobals ) {
            // 对指定元素发触事件ajaxSuccess或者ajaxError
            globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
                [ jqXHR, s, isSuccess ? success : error ] );
        }

        // 回调成完后的Callbacks队列
        completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );

        // 如果须要发触全局事件
        if ( fireGlobals ) {
            // 对指定元素发触事件ajaxComplete
            globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
            // 该ajax发触终了,标记active减1,如果为0,证明有所ajax束结
            if ( !( --jQuery.active ) ) {
                // 发触ajaxStop事件
                jQuery.event.trigger("ajaxStop");
            }
        }
    }

    // 回返寨山xhr
    return jqXHR;
};
 

 

文章结束给大家分享下程序员的一些笑话语录: 手机终究会变成PC,所以ip会比wm更加畅销,但是有一天手机强大到一定程度了就会发现只有wm的支持才能完美享受。就好比树和草,草长得再高也是草,时间到了条件成熟了树就会窜天高了。www.ishuo.cn


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值