gpt4 book ai didi

javascript - 动态加载外部 Javascript 文件,并等待其加载 - 不使用 JQuery

转载 作者:行者123 更新时间:2023-12-03 01:54:40 24 4
gpt4 key购买 nike

我正在尝试动态加载外部 .js 文件(根据我从用户那里获得的输入)。目前我的代码如下所示:

function createScript(src, id) {
if (document.getElementById(id) == null) {
var newScript = document.createElement('script');
newScript.setAttribute("type", "text/javascript");
newScript.setAttribute("src", src);
newScript.setAttribute("id", id);
document.getElementsByTagName("head")[0].appendChild(newScript);
}
}

这样的工作。它确实加载了脚本,但如果我尝试调用新脚本中定义的函数,它将无法工作。奇怪的是,如果我等待一秒钟(使用 alert("test") 或类似的东西),脚本就会起作用。

我猜是因为浏览器添加了 <script>立即标记,但“读取”.js 文件内的脚本需要更长的时间。我尝试玩 "typeof testfunction === 'function'"有一些变化,但没有运气。

有什么好的方法吗?

最佳答案

2017 年 2 月 21 日 - jQuery 是如何做到的

jQuery.getScript现在只是 jQuery.get

的包装器
getScript: function( url, callback ) {
return jQuery.get( url, undefined, callback, "script" );
}

jQuery.get只是 jQuery.ajax 的包装 - 它是使用元编程定义的...

jQuery.each( [ <b>"get"</b>, "post" ], function( i, method ) {
jQuery[ method ] = function( url, data, callback, type ) {

// Shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = undefined;
}

// The url can be an options object (which then must have .url)
return jQuery.ajax( jQuery.extend( {
url: url,
type: method,
dataType: type,
data: data,
success: callback
}, jQuery.isPlainObject( url ) && url ) );
};
} );

jQuery.ajax这是430+LOC怪物吗

ajax: function( url, options ) {

// If url is an object, simulate pre-1.5 signature
if ( typeof url === "object" ) {
options = url;
url = undefined;
}

// Force options to be an object
options = options || {};

var transport,

// URL without anti-cache param
cacheURL,

// Response headers
responseHeadersString,
responseHeaders,

// timeout handle
timeoutTimer,

// Url cleanup var
urlAnchor,

// Request state (becomes false upon send and true upon completion)
completed,

// To know if global events are to be dispatched
fireGlobals,

// Loop variable
i,

// uncached part of the url
uncached,

// Create the final options object
s = jQuery.ajaxSetup( {}, options ),

// Callbacks context
callbackContext = s.context || s,

// Context for global events is callbackContext if it is a DOM node or jQuery collection
globalEventContext = s.context &&
( callbackContext.nodeType || callbackContext.jquery ) ?
jQuery( callbackContext ) :
jQuery.event,

// Deferreds
deferred = jQuery.Deferred(),
completeDeferred = jQuery.Callbacks( "once memory" ),

// Status-dependent callbacks
statusCode = s.statusCode || {},

// Headers (they are sent all at once)
requestHeaders = {},
requestHeadersNames = {},

// Default abort message
strAbort = "canceled",

// Fake xhr
jqXHR = {
readyState: 0,

// Builds headers hashtable if needed
getResponseHeader: function( key ) {
var match;
if ( completed ) {
if ( !responseHeaders ) {
responseHeaders = {};
while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
}
}
match = responseHeaders[ key.toLowerCase() ];
}
return match == null ? null : match;
},

// Raw string
getAllResponseHeaders: function() {
return completed ? responseHeadersString : null;
},

// Caches the header
setRequestHeader: function( name, value ) {
if ( completed == null ) {
name = requestHeadersNames[ name.toLowerCase() ] =
requestHeadersNames[ name.toLowerCase() ] || name;
requestHeaders[ name ] = value;
}
return this;
},

// Overrides response content-type header
overrideMimeType: function( type ) {
if ( completed == null ) {
s.mimeType = type;
}
return this;
},

// Status-dependent callbacks
statusCode: function( map ) {
var code;
if ( map ) {
if ( completed ) {

// Execute the appropriate callbacks
jqXHR.always( map[ jqXHR.status ] );
} else {

// Lazy-add the new callbacks in a way that preserves old ones
for ( code in map ) {
statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
}
}
}
return this;
},

// Cancel the request
abort: function( statusText ) {
var finalText = statusText || strAbort;
if ( transport ) {
transport.abort( finalText );
}
done( 0, finalText );
return this;
}
};

// Attach deferreds
deferred.promise( jqXHR );

// Add protocol if not provided (prefilters might expect it)
// Handle falsy url in the settings object (#10093: consistency with old signature)
// We also use the url parameter if available
s.url = ( ( url || s.url || location.href ) + "" )
.replace( rprotocol, location.protocol + "//" );

// Alias method option to type as per ticket #12004
s.type = options.method || options.type || s.method || s.type;

// Extract dataTypes list
s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];

// A cross-domain request is in order when the origin doesn't match the current origin.
if ( s.crossDomain == null ) {
urlAnchor = document.createElement( "a" );

// Support: IE <=8 - 11, Edge 12 - 13
// IE throws exception on accessing the href property if url is malformed,
// e.g. http://example.com:80x/
try {
urlAnchor.href = s.url;

// Support: IE <=8 - 11 only
// Anchor's host property isn't correctly set when s.url is relative
urlAnchor.href = urlAnchor.href;
s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
urlAnchor.protocol + "//" + urlAnchor.host;
} catch ( e ) {

// If there is an error parsing the URL, assume it is crossDomain,
// it can be rejected by the transport if it is invalid
s.crossDomain = true;
}
}

// Convert data if not already a string
if ( s.data && s.processData && typeof s.data !== "string" ) {
s.data = jQuery.param( s.data, s.traditional );
}

// Apply prefilters
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );

// If request was aborted inside a prefilter, stop there
if ( completed ) {
return jqXHR;
}

// We can fire global events as of now if asked to
// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
fireGlobals = jQuery.event && s.global;

// Watch for a new set of requests
if ( fireGlobals && jQuery.active++ === 0 ) {
jQuery.event.trigger( "ajaxStart" );
}

// Uppercase the type
s.type = s.type.toUpperCase();

// Determine if request has content
s.hasContent = !rnoContent.test( s.type );

// Save the URL in case we're toying with the If-Modified-Since
// and/or If-None-Match header later on
// Remove hash to simplify url manipulation
cacheURL = s.url.replace( rhash, "" );

// More options handling for requests with no content
if ( !s.hasContent ) {

// Remember the hash so we can put it back
uncached = s.url.slice( cacheURL.length );

// If data is available, append data to url
if ( s.data ) {
cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;

// #9682: remove data so that it's not used in an eventual retry
delete s.data;
}

// Add or update anti-cache param if needed
if ( s.cache === false ) {
cacheURL = cacheURL.replace( rantiCache, "$1" );
uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached;
}

// Put hash and anti-cache on the URL that will be requested (gh-1732)
s.url = cacheURL + uncached;

// Change '%20' to '+' if this is encoded form body content (gh-2658)
} else if ( s.data && s.processData &&
( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
s.data = s.data.replace( r20, "+" );
}

// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
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 ] );
}
}

// Set the correct header, if data is being sent
if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
jqXHR.setRequestHeader( "Content-Type", s.contentType );
}

// Set the Accepts header for the server, depending on the dataType
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[ "*" ]
);

// Check for headers option
for ( i in s.headers ) {
jqXHR.setRequestHeader( i, s.headers[ i ] );
}

// Allow custom headers/mimetypes and early abort
if ( s.beforeSend &&
( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {

// Abort if not done already and return
return jqXHR.abort();
}

// Aborting is no longer a cancellation
strAbort = "abort";

// Install callbacks on deferreds
completeDeferred.add( s.complete );
jqXHR.done( s.success );
jqXHR.fail( s.error );

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

// If no transport, we auto-abort
if ( !transport ) {
done( -1, "No Transport" );
} else {
jqXHR.readyState = 1;

// Send global event
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
}

// If request was aborted inside ajaxSend, stop there
if ( completed ) {
return jqXHR;
}

// Timeout
if ( s.async && s.timeout > 0 ) {
timeoutTimer = window.setTimeout( function() {
jqXHR.abort( "timeout" );
}, s.timeout );
}

try {
completed = false;
transport.send( requestHeaders, done );
} catch ( e ) {

// Rethrow post-completion exceptions
if ( completed ) {
throw e;
}

// Propagate others as results
done( -1, e );
}
}

// Callback for when everything is done
function done( status, nativeStatusText, responses, headers ) {
var isSuccess, success, error, response, modified,
statusText = nativeStatusText;

// Ignore repeat invocations
if ( completed ) {
return;
}

completed = true;

// Clear timeout if it exists
if ( timeoutTimer ) {
window.clearTimeout( timeoutTimer );
}

// Dereference transport for early garbage collection
// (no matter how long the jqXHR object will be used)
transport = undefined;

// Cache response headers
responseHeadersString = headers || "";

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

// Determine if successful
isSuccess = status >= 200 && status < 300 || status === 304;

// Get response data
if ( responses ) {
response = ajaxHandleResponses( s, jqXHR, responses );
}

// Convert no matter what (that way responseXXX fields are always set)
response = ajaxConvert( s, response, jqXHR, isSuccess );

// If successful, handle type chaining
if ( isSuccess ) {

// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
modified = jqXHR.getResponseHeader( "Last-Modified" );
if ( modified ) {
jQuery.lastModified[ cacheURL ] = modified;
}
modified = jqXHR.getResponseHeader( "etag" );
if ( modified ) {
jQuery.etag[ cacheURL ] = modified;
}
}

// if no content
if ( status === 204 || s.type === "HEAD" ) {
statusText = "nocontent";

// if not modified
} else if ( status === 304 ) {
statusText = "notmodified";

// If we have data, let's convert it
} else {
statusText = response.state;
success = response.data;
error = response.error;
isSuccess = !error;
}
} else {

// Extract error from statusText and normalize for non-aborts
error = statusText;
if ( status || !statusText ) {
statusText = "error";
if ( status < 0 ) {
status = 0;
}
}
}

// Set data for the fake xhr object
jqXHR.status = status;
jqXHR.statusText = ( nativeStatusText || statusText ) + "";

// Success/Error
if ( isSuccess ) {
deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
} else {
deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
}

// Status-dependent callbacks
jqXHR.statusCode( statusCode );
statusCode = undefined;

if ( fireGlobals ) {
globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
[ jqXHR, s, isSuccess ? success : error ] );
}

// Complete
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );

if ( fireGlobals ) {
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );

// Handle the global AJAX counter
if ( !( --jQuery.active ) ) {
jQuery.event.trigger( "ajaxStop" );
}
}
}

return jqXHR;
}

所以,是的,尝试从这段代码中删除所有依赖项显然是荒谬的。如果您想使用 jQuery 的方法异步加载外部脚本,最好只包含 jQuery。

或者,考虑完全使用不同的工具。

<小时/>

<强> July 16, 2013 - 来自没有依赖项的 jQuery 内核 [需要源代码引用]

function getScript(src, callback) {
var s = document.createElement('script');
s.src = src;
s.async = true;
s.onreadystatechange = s.onload = function() {
if (!callback.done && (!s.readyState || /loaded|complete/.test(s.readyState))) {
callback.done = true;
callback();
}
};
document.querySelector('head').appendChild(s);
}

关于javascript - 动态加载外部 Javascript 文件,并等待其加载 - 不使用 JQuery,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8586446/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com