Javascript 异步加载脚本
我正在使用JQuery中的几个插件、自定义小部件和一些其他库。因此,我有几个.js和.css文件。我需要为我的网站创建一个加载程序,因为加载需要一些时间。如果我能在导入所有以下内容之前显示加载程序,那就太好了:Javascript 异步加载脚本,javascript,ajax,html,asynchronous,Javascript,Ajax,Html,Asynchronous,我正在使用JQuery中的几个插件、自定义小部件和一些其他库。因此,我有几个.js和.css文件。我需要为我的网站创建一个加载程序,因为加载需要一些时间。如果我能在导入所有以下内容之前显示加载程序,那就太好了: <script type="text/javascript" src="js/jquery-1.6.2.min.js"></script> <script type="text/javascript" src="js/myFunctions.js">&
<script type="text/javascript" src="js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="js/myFunctions.js"></script>
<link type="text/css" href="css/main.css" rel="stylesheet" />
...
....
etc
由于某种原因,当我对所有文件执行相同的操作时,页面无法工作。我一直在努力寻找问题所在,但就是找不到。首先,我认为这可能是因为一些javascript函数依赖于其他函数。但是我使用超时功能以正确的顺序加载了它们,当一个完成时,我继续下一个,页面仍然表现出奇怪的行为。例如,我不能点击链接等。。。但动画仍然有效
无论如何
这是我一直在想的。。。我相信浏览器有一个缓存,这就是为什么第一次加载页面需要很长时间,下一次加载速度很快的原因。所以我想做的是用一个异步加载所有这些文件的页面替换index.html页面。ajax加载完成后,所有这些文件都会重定向到我计划使用的页面。使用该页面时,加载不会花费很长时间,因为文件应该包含在浏览器的缓存中。在我的索引页面(异步加载.js和.css文件的页面)上,我不在乎出错。我将只是显示一个加载器和重定向页面时完成
这是一个好的选择吗?或者我应该继续尝试异步实现这些方法吗
编辑 我以异步方式加载所有内容的方式如下:
importScripts();
function importScripts()
{
//import: jquery-ui-1.8.16.custom.min.js
getContent("js/jquery-1.6.2.min.js",function (code) {
var s = document.createElement('script');
s.type = 'text/javascript';
//s.async = true;
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext1,1);
});
//import: jquery-ui-1.8.16.custom.min.js
function insertNext1()
{
getContent("js/jquery-ui-1.8.16.custom.min.js",function (code) {
var s = document.createElement('script');
s.type = 'text/javascript';
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext2,1);
});
}
//import: jquery-ui-1.8.16.custom.css
function insertNext2()
{
getContent("css/custom-theme/jquery-ui-1.8.16.custom.css",function (code) {
var s = document.createElement('link');
s.type = 'text/css';
s.rel ="stylesheet";
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext3,1);
});
}
//import: main.css
function insertNext3()
{
getContent("css/main.css",function (code) {
var s = document.createElement('link');
s.type = 'text/css';
s.rel ="stylesheet";
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext4,1);
});
}
//import: jquery.imgpreload.min.js
function insertNext4()
{
getContent("js/farinspace/jquery.imgpreload.min.js",function (code) {
var s = document.createElement('script');
s.type = 'text/javascript';
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext5,1);
});
}
//import: marquee.js
function insertNext5()
{
getContent("js/marquee.js",function (code) {
var s = document.createElement('script');
s.type = 'text/javascript';
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext6,1);
});
}
//import: marquee.css
function insertNext6()
{
getContent("css/marquee.css",function (code) {
var s = document.createElement('link');
s.type = 'text/css';
s.rel ="stylesheet";
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext,1);
});
}
function insertNext()
{
setTimeout(pageReadyMan,10);
}
}
// get the content of url and pass that content to specified function
function getContent( url, callBackFunction )
{
// attempt to create the XMLHttpRequest and make the request
try
{
var asyncRequest; // variable to hold XMLHttpRequest object
asyncRequest = new XMLHttpRequest(); // create request object
// register event handler
asyncRequest.onreadystatechange = function(){
stateChange(asyncRequest, callBackFunction);
}
asyncRequest.open( 'GET', url, true ); // prepare the request
asyncRequest.send( null ); // send the request
} // end try
catch ( exception )
{
alert( 'Request failed.' );
} // end catch
} // end function getContent
// call function whith content when ready
function stateChange(asyncRequest, callBackFunction)
{
if ( asyncRequest.readyState == 4 && asyncRequest.status == 200 )
{
callBackFunction(asyncRequest.responseText);
} // end if
} // end function stateChange
奇怪的是,所有样式的工作加上所有javascript函数。由于某种原因,该页面被冻结了…我建议您先缩小文件,看看这是否能给您带来足够大的速度提升。如果您的主机运行缓慢,可以尝试将静态内容放在CDN上。您可能会发现这篇wiki文章很有趣:
它解释了如何以及何时使用这种技术。嗯,
x.parentNode
返回HEAD元素,因此您将在HEAD标记之前插入脚本。也许这就是问题所在
请尝试
x.parentNode.appendChild()
。脚本加载如此缓慢的一个原因是,如果在加载页面时运行所有脚本,如下所示:
callMyFunctions();
const loader = new Loader({
src: 'cdn.segment.com/analytics.js',
global: 'Segment',
})
// scriptToLoad will now be a reference to `window.Segment`
const scriptToLoad = await loader.load()
而不是:
$(window).load(function() {
callMyFunctions();
});
第二位脚本将等待浏览器完全加载所有Javascript代码,然后再开始执行任何脚本,从而向用户显示页面加载速度更快
如果您希望通过缩短加载时间来增强用户体验,我不会选择“加载屏幕”选项。在我看来,这比让页面加载更慢要烦人得多。异步加载的两种解决方案:
//this function will work cross-browser for loading scripts asynchronously
function loadScript(src, callback)
{
var s,
r,
t;
r = false;
s = document.createElement('script');
s.type = 'text/javascript';
s.src = src;
s.onload = s.onreadystatechange = function() {
//console.log( this.readyState ); //uncomment this line to see which ready states are called.
if ( !r && (!this.readyState || this.readyState == 'complete') )
{
r = true;
callback();
}
};
t = document.getElementsByTagName('script')[0];
t.parentNode.insertBefore(s, t);
}
如果页面上已经有jQuery,只需使用:
*
此外,您的脚本可能在文档加载完成之前加载/执行,这意味着您需要等待document.ready
,然后才能将事件绑定到元素
在没有看到代码的情况下,无法具体说明您的问题是什么
最简单的解决方案是将所有脚本内联在页面底部,这样它们在执行时不会阻止HTML内容的加载。它还避免了必须异步加载每个所需脚本的问题
如果您有一个特别奇特的交互,但并不总是使用它,它需要某种更大的脚本,那么在需要之前避免加载该特定脚本(延迟加载)可能会很有用
*
对于任何可以使用现代功能(如对象)的人来说,
loadScript
功能变得非常简单:
function loadScript(src) {
return new Promise(function (resolve, reject) {
var s;
s = document.createElement('script');
s.src = src;
s.onload = resolve;
s.onerror = reject;
document.head.appendChild(s);
});
}
请注意,此版本不再接受回调
参数,因为返回的承诺将处理回调。以前是loadScript(src,callback)
现在是loadScript(src)。然后是(callback)
这有额外的好处,能够检测和处理故障,例如,一个人可以调用
loadScript(cdnSource)
.catch(loadScript.bind(null, localSource))
.then(successCallback, failureCallback);
…而且它可以优雅地处理CDN中断。我建议您看看。它是一个小型的轻量级库,您可以异步加载javascript,并具有一些功能,允许您检查文件是否已加载,并在指定的其他文件中执行脚本 下面是加载jquery的示例:
Modernizr.load([
{
load: '//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js',
complete: function () {
if ( !window.jQuery ) {
Modernizr.load('js/libs/jquery-1.6.1.min.js');
}
}
},
{
// This will wait for the fallback to load and
// execute if it needs to.
load: 'needs-jQuery.js'
}
]);
我异步加载了脚本(HTML5具有该功能),当加载完所有脚本后,我将页面重定向到index2.html,其中index2.html使用相同的库。因为一旦页面重定向到index2.html,浏览器就会有一个缓存,index2.html会在不到一秒钟的时间内加载,因为它拥有加载页面所需的全部内容。在我的index.html页面中,我还加载了我计划使用的图像,以便浏览器将这些图像放在缓存中。因此,我的index.html如下所示:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Project Management</title>
<!-- the purpose of this page is to load all the scripts on the browsers cache so that pages can load fast from now on -->
<script type="text/javascript">
function stylesheet(url) {
var s = document.createElement('link');
s.type = 'text/css';
s.async = true;
s.src = url;
var x = document.getElementsByTagName('head')[0];
x.appendChild(s);
}
function script(url) {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = url;
var x = document.getElementsByTagName('head')[0];
x.appendChild(s);
}
//load scritps to the catche of browser
(function () {
stylesheet('css/custom-theme/jquery-ui-1.8.16.custom.css');
stylesheet('css/main.css');
stylesheet('css/marquee.css');
stylesheet('css/mainTable.css');
script('js/jquery-ui-1.8.16.custom.min.js');
script('js/jquery-1.6.2.min.js');
script('js/myFunctions.js');
script('js/farinspace/jquery.imgpreload.min.js');
script('js/marquee.js');
})();
</script>
<script type="text/javascript">
// once the page is loaded go to index2.html
window.onload = function () {
document.location = "index2.html";
}
</script>
</head>
<body>
<div id="cover" style="position:fixed; left:0px; top:0px; width:100%; height:100%; background-color:Black; z-index:100;">Loading</div>
<img src="images/home/background.png" />
<img src="images/home/3.png"/>
<img src="images/home/6.jpg"/>
<img src="images/home/4.png"/>
<img src="images/home/5.png"/>
<img src="images/home/8.jpg"/>
<img src="images/home/9.jpg"/>
<img src="images/logo.png"/>
<img src="images/logo.png"/>
<img src="images/theme/contentBorder.png"/>
</body>
</html>
项目管理
函数样式表(url){
var s=document.createElement('link');
s、 类型='text/css';
s、 异步=真;
s、 src=url;
var x=document.getElementsByTagName('head')[0];
x、 儿童;
}
函数脚本(url){
var s=document.createElement('script');
s、 类型='text/javascript';
s、 异步=真;
s、 src=url;
var x=document.getElementsByTagName('head')[0];
x、 儿童;
}
//将scritps加载到浏览器的catch中
(函数(){
样式表('css/custom-theme/jquery-ui-1.8.16.custom.css');
样式表('css/main.css');
样式表('css/marquee.css');
(function() {
var prot = ("https:"===document.location.protocol?"https://":"http://");
var scripts = [
"path/to/first.js",
"path/to/second.js",
"path/to/third.js"
];
function completed() { console.log('completed'); } // FIXME: remove logs
function checkStateAndCall(path, callback) {
var _success = false;
return function() {
if (!_success && (!this.readyState || (this.readyState == 'complete'))) {
_success = true;
console.log(path, 'is ready'); // FIXME: remove logs
callback();
}
};
}
function asyncLoadScripts(files) {
function loadNext() { // chain element
if (!files.length) completed();
var path = files.shift();
var scriptElm = document.createElement('script');
scriptElm.type = 'text/javascript';
scriptElm.async = true;
scriptElm.src = prot+path;
scriptElm.onload = scriptElm.onreadystatechange = \
checkStateAndCall(path, loadNext); // load next file in chain when
// this one will be ready
var headElm = document.head || document.getElementsByTagName('head')[0];
headElm.appendChild(scriptElm);
}
loadNext(); // start a chain
}
asyncLoadScripts(scripts);
})();
function loadScript(src, callback, args) {
var s, r, t;
r = false;
s = document.createElement('script');
s.type = 'text/javascript';
s.src = src;
if (typeof(callback) === 'function') {
s.onload = s.onreadystatechange = function() {
if (!r && (!this.readyState || this.readyState === 'complete')) {
r = true;
callback.apply(args);
}
};
};
t = document.getElementsByTagName('script')[0];
t.parent.insertBefore(s, t);
}
<script async src="siteScript.js" onload="myInit()"></script>
<script defer src="siteScript.js" onload="myInit()"></script>
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js?onload=onLoadCallback';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
// put all your JS files here, in correct order
const libs = {
"jquery": "https://code.jquery.com/jquery-2.1.4.min.js",
"bxSlider": "https://cdnjs.cloudflare.com/ajax/libs/bxslider/4.2.5/jquery.bxslider.min.js",
"angular": "https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.2/angular.min.js",
"ngAnimate": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.2/angular-animate.min.js"
}
const loadedLibs = {}
let counter = 0
const loadAsync = function(lib) {
var http = new XMLHttpRequest()
http.open("GET", libs[lib], true)
http.onload = () => {
loadedLibs[lib] = http.responseText
if (++counter == Object.keys(libs).length) startScripts()
}
http.send()
}
const startScripts = function() {
for (var lib in libs) eval(loadedLibs[lib])
console.log("allLoaded")
}
for (var lib in libs) loadAsync(lib)
<script async>...</script>
fetcInject([
'js/jquery-1.6.2.min.js',
'js/marquee.js',
'css/marquee.css',
'css/custom-theme/jquery-ui-1.8.16.custom.css',
'css/main.css'
]).then(() => {
'js/jquery-ui-1.8.16.custom.min.js',
'js/farinspace/jquery.imgpreload.min.js'
})
[
'script1.js',
'script2.js',
'script3.js',
'script4.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});
var scripts = [
'script1.js',
'script2.js',
'script3.js',
'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];
// Watch scripts load in IE
function stateChange() {
// Execute as many scripts in order as we can
var pendingScript;
while (pendingScripts[0] && ( pendingScripts[0].readyState == 'loaded' || pendingScripts[0].readyState == 'complete' ) ) {
pendingScript = pendingScripts.shift();
// avoid future loading events from this script (eg, if src changes)
pendingScript.onreadystatechange = null;
// can't just appendChild, old IE bug if element isn't closed
firstScript.parentNode.insertBefore(pendingScript, firstScript);
}
}
// loop through our script urls
while (src = scripts.shift()) {
if ('async' in firstScript) { // modern browsers
script = document.createElement('script');
script.async = false;
script.src = src;
document.head.appendChild(script);
}
else if (firstScript.readyState) { // IE<10
// create a script and add it to our todo pile
script = document.createElement('script');
pendingScripts.push(script);
// listen for state changes
script.onreadystatechange = stateChange;
// must set src AFTER adding onreadystatechange listener
// else we’ll miss the loaded event for cached scripts
script.src = src;
}
else { // fall back to defer
document.write('<script src="' + src + '" defer></'+'script>');
}
}
export default class ScriptLoader {
constructor (options) {
const { src, global, protocol = document.location.protocol } = options
this.src = src
this.global = global
this.protocol = protocol
this.isLoaded = false
}
loadScript () {
return new Promise((resolve, reject) => {
// Create script element and set attributes
const script = document.createElement('script')
script.type = 'text/javascript'
script.async = true
script.src = `${this.protocol}//${this.src}`
// Append the script to the DOM
const el = document.getElementsByTagName('script')[0]
el.parentNode.insertBefore(script, el)
// Resolve the promise once the script is loaded
script.addEventListener('load', () => {
this.isLoaded = true
resolve(script)
})
// Catch any errors while loading the script
script.addEventListener('error', () => {
reject(new Error(`${this.src} failed to load.`))
})
})
}
load () {
return new Promise(async (resolve, reject) => {
if (!this.isLoaded) {
try {
await this.loadScript()
resolve(window[this.global])
} catch (e) {
reject(e)
}
} else {
resolve(window[this.global])
}
})
}
}
const loader = new Loader({
src: 'cdn.segment.com/analytics.js',
global: 'Segment',
})
// scriptToLoad will now be a reference to `window.Segment`
const scriptToLoad = await loader.load()