我正在使用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> <link type="text/css" href="css/main.css" rel="stylesheet" /> ... .... etc
我找到了一些教程,这些教程使我能够异步导入JavaScript库。例如,我可以做类似的事情:
(function () { var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true; s.src = 'js/jquery-ui-1.8.16.custom.min.js'; var x = document.getElementsByTagName('script')[0]; x.parentNode.insertBefore(s, x); })();
由于某种原因,当我对所有文件执行相同操作时,页面将无法正常工作。我已经尝试了很长时间,试图找到问题所在,但我只是找不到。首先,我认为这可能是因为某些javascript函数依赖于其他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函数。该页面由于某种原因被冻结…
异步加载的几种解决方案:
//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,请使用:
$.getScript(url, successCallback)*
$.getScript(url, successCallback)
此外,有可能在文档加载完成之前就已经加载/执行了脚本,这意味着您需要等待document.ready事件才能绑定到元素。
document.ready
在不查看代码的情况下,无法明确分辨出您的问题是什么。
最简单的解决方案是将所有脚本内联在页面底部,这样它们就不会在执行时阻止HTML内容的加载。它还避免了必须异步加载每个所需脚本的问题。
如果您有一个并不常用的特别花哨的交互功能,并且需要某种较大的脚本,那么避免在需要之前加载该特定脚本(延迟加载)会很有用。
对于可以使用现代功能(例如Promise对象)的任何人,该loadScript功能都变得更加简单:
Promise
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); }); }
请注意,此版本不再接受callback参数,因为返回的Promise将处理回调。以前应该是loadScript(src, callback)现在loadScript(src).then(callback)。
callback
loadScript(src, callback)
loadScript(src).then(callback)
这具有能够检测和处理故障的额外好处,例如可以打电话给…
loadScript(cdnSource) .catch(loadScript.bind(null, localSource)) .then(successCallback, failureCallback);
…并且它将优雅地处理CDN中断。