用jQuery的append方法插入script节点时,为何请求相应的js资源文件会附带随机的字符串?


如果直接将script节点以下例子的方式(或其他appendTo等方法)插入文档中时,相应的js文件资源请求,总是带有后缀 “?_="和一串随机数字,有点类似版本号。而且每次刷新页面时,这个随机数字字符串是不一样的,这样导致每次都重新请求和下载该资源,而不使用缓存。 sob


 $("body").append('<script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>')

使用 以下 或 document.write 原生来写是没有上面那样的问题。

var elem = document.createElement('script');
elem.src = "http://libs.useso.com/js/jquery/1.9.1/jquery.min.js";
document.querySelector('body').appendChild(elem);

那么 jQuery到底封装了什么呢,看 源代码 也看不出个所以然,望哪位高人能指点迷津一下。

jquery bug 前端 JavaScript

kbmgs 9 years, 2 months ago

特地去看了下源码


 append: function() {
    return this.domManip( arguments, function( elem ) {
        if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
            var target = manipulationTarget( this, elem );
            target.appendChild( elem );
        }
    });
}

domManip: function( args, callback ) {

    // Flatten any nested arrays
    args = concat.apply( [], args );

    var fragment, first, scripts, hasScripts, node, doc,
        i = 0,
        l = this.length,
        set = this,
        iNoClone = l - 1,
        value = args[ 0 ],
        isFunction = jQuery.isFunction( value );

    // We can't cloneNode fragments that contain checked, in WebKit
    if ( isFunction ||
            ( l > 1 && typeof value === "string" &&
                !support.checkClone && rchecked.test( value ) ) ) {
        return this.each(function( index ) {
            var self = set.eq( index );
            if ( isFunction ) {
                args[ 0 ] = value.call( this, index, self.html() );
            }
            self.domManip( args, callback );
        });
    }

    if ( l ) {
        fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
        first = fragment.firstChild;

        if ( fragment.childNodes.length === 1 ) {
            fragment = first;
        }

        if ( first ) {
            scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
            hasScripts = scripts.length;

            // Use the original fragment for the last item instead of the first because it can end up
            // being emptied incorrectly in certain situations (#8070).
            for ( ; i < l; i++ ) {
                node = fragment;

                if ( i !== iNoClone ) {
                    node = jQuery.clone( node, true, true );

                    // Keep references to cloned scripts for later restoration
                    if ( hasScripts ) {
                        // Support: QtWebKit
                        // jQuery.merge because push.apply(_, arraylike) throws
                        jQuery.merge( scripts, getAll( node, "script" ) );
                    }
                }

                callback.call( this[ i ], node, i );
            }

            if ( hasScripts ) {
                doc = scripts[ scripts.length - 1 ].ownerDocument;

                // Reenable scripts
                jQuery.map( scripts, restoreScript );

                // Evaluate executable scripts on first document insertion
                for ( i = 0; i < hasScripts; i++ ) {
                    node = scripts[ i ];
                    if ( rscriptType.test( node.type || "" ) &&
                        !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {

                        if ( node.src ) {
                            // Optional AJAX dependency, but won't run scripts if not present
                            if ( jQuery._evalUrl ) {
                                jQuery._evalUrl( node.src );
                            }
                        } else {
                            jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
                        }
                    }
                }
            }
        }
    }

    return this;
}

在domManip方法中找到这行代码


 callback.call( this[ i ], node, i );

这个是往DOM中插入script标签的,不过插入的是这个玩意儿,代码执行到这
图片描述
这里是当前Element里的结构
图片描述

这个时候jQuery已经偷梁换柱了,拷贝了我们插入的内容,并修改了类型。类型不对,根本没有当作脚本解析。所以并不会去请求js。
代码继续往下跑,最后执行了这个


 jQuery._evalUrl( node.src );

jQuery._evalUrl = function( url ) {
    return jQuery.ajax({
        url: url,
        type: "GET",
        dataType: "script",
        async: false,
        global: false,
        "throws": true
    });
};

是jQuery自己发起的get请求。到这,这里的随机数字怎么出现很明显了,是ajax里的配置。@Chobits的回答。

以上

yamada answered 9 years, 2 months ago

dafanxu answered 9 years, 2 months ago

Your Answer