使用回调异步加载JavaScript文件

时间:2010-06-13 15:16:43

标签: javascript ajax asynchronous design-patterns

我正在尝试编写一个超简单的解决方案来异步加载一堆JS文件。到目前为止,我有以下脚本。但是,当脚本未实际加载时,有时会调用回调,这会导致找不到变量错误。如果我刷新页面有时它只是工作,因为我猜文件是直接来自缓存,因此比调用回调更快,这是非常奇怪的?

var Loader = function () {

}
Loader.prototype = {
    require: function (scripts, callback) {
        this.loadCount      = 0;
        this.totalRequired  = scripts.length;
        this.callback       = callback;

        for (var i = 0; i < scripts.length; i++) {
            this.writeScript(scripts[i]);
        }
    },
    loaded: function (evt) {
        this.loadCount++;

        if (this.loadCount == this.totalRequired && typeof this.callback == 'function') this.callback.call();
    },
    writeScript: function (src) {
        var self = this;
        var s = document.createElement('script');
        s.type = "text/javascript";
        s.async = true;
        s.src = src;
        s.addEventListener('load', function (e) { self.loaded(e); }, false);
        var head = document.getElementsByTagName('head')[0];
        head.appendChild(s);
    }
}

无论如何都要测试JS文件是否已完全加载,而不是在实际的JS文件本身中添加一些东西,因为我想使用相同的模式来加载我的控制库(GMaps等)。

在标记之前调用代码。

var l = new Loader();
l.require([
    "ext2.js",
    "ext1.js"], 
    function() {
        var config = new MSW.Config();
        Refraction.Application().run(MSW.ViewMapper, config);
        console.log('All Scripts Loaded');
    });

感谢您的帮助。

7 个答案:

答案 0 :(得分:4)

jQuery怎么样......

$.getScript('abc.js'); 

上面的代码将异步加载“abc.js”脚本文件....

答案 1 :(得分:3)

我建议你使用像JcorsLoader这样的小型加载器javascript(只有647B和Gzip)

JcorsLoader.load(
                "http://xxxx/jquery.min.js",
                function() {
                    $("#demo").html("jQuery Loaded");
                },
                "http://xxxx/jquery.cookie.js",
                function() {  
                    $.cookie('not_existing'); 
                }
            );

并行加载多个js并按顺序执行而不阻止DOMReady或onload。

https://github.com/pablomoretti/jcors-loader

答案 2 :(得分:2)

我所知道的代码没有任何问题,这只是Chrome中的一个错误(它也可以通过window.onload实现。)

我将它添加到“加载”功能中触发的函数中。如果变量存在,则执行JS代码,但如果不存在,则使用setTimeout在500ms左右再次检查。

答案 3 :(得分:2)

万一你发现这个有用,我已经创建了一个异步实用程序库,可以让你编写上面的代码:

var Loader = function () {}

Loader.prototype = {
    require: function (scripts, callback) {
        async.map(scripts, this.writeScript, callback);
    },
    writeScript: function(src, callback) {
        var s = document.createElement('script');
        s.type = "text/javascript";
        s.src = src;
        s.addEventListener('load', function (e) { callback(null, e); }, false);
        var head = document.getElementsByTagName('head')[0];
        head.appendChild(s);
    }
}

如果您正在进行大量异步调用,它具有一些非常强大的功能:)

http://caolanmcmahon.com/async.html

答案 4 :(得分:0)

就像Aaron说Chrome中有一个错误,但IE和其他浏览器也存在问题。

我尝试了不同的方法来创建我的懒惰加载器,我遇到了很多问题:

  • 添加&lt; script&gt; tag:资源管理器和其他浏览器中的脚本事件(onload,onerror等)的问题
  • 使用ajax读取脚本并解析文本(使用eval,它是javascript所以不要担心它不是evil):非常难以调试(它被解析为没有注释的单行,所以你不知道什么行给出你错了)
  • 使用ajax读取脚本并添加&lt; script&gt;带有脚本文本的标记:在所有浏览器上都能很好地工作; 你可以使用相同的功能创建异步和同步加载,你也可以很好地控制错误,加载等(如果你知道ajax的基础知识,你应该知道如何处理各种http状态),这就是我的建议。

答案 5 :(得分:0)

jcors-loader.js无法在Internet Explorer中运行...

Index.html

<html>
    <head>
    <script type="text/javascript" src="/js/jcors-loader.js"></script>
    <script>
        JcorsLoader.load(
                "js/jquery-1.8.0.js",
                "/js/alertme.js",
                function() {
                    $("#result").text("TEST OK");
                }
        );

    </script>
    </head>
    <body>
    <h1 id="result"></h1>
    </body>
    </html>

<强> alertme.js

警报( “加载”);

这在chrome和firefox中运行良好它显示“TEST OK”并弹出...但在IE中没有消息或警报(7,8,9)...任何帮助将不胜感激。

答案 6 :(得分:-2)

Aku menggabungkan scrpit callback dengan tooltip,didalam模板博主。 kemudian didalamnya ditambahkan script callbak menggunakan javascipt

Script callback with tooltip

<style>
/* Tooltip container */
.tooltip {
    position: relative;
    display: inline-block;
    text-transform: italic;
    color: blue;
    border-bottom: 1px dotted black;
}


.tooltip .tooltiptext {
    visibility: hidden;
    width: 400px;
    background-color: #fff;
    border: 2px solid #cc6611;
    color: black;
    text-align: left;
	top: 0; left: 6px;
    border-radius: 6px;
	box-shadow: 0 2px 4px -2px #716e6c;
    padding: 15px;
    position: absolute;
    z-index: 999;
    top: 90%;
    left: 10%;
    margin-left: -10px;
}

.tooltip .tooltiptext::after {
    content: "";
    position: absolute;
    bottom: 100%;
    left: 10%;
    margin-left: -10px;
    border-width: 10px;
    border-style: solid;
    border-color: transparent transparent #cc6611 transparent;
}

.tooltip:hover .tooltiptext {
    visibility: visible;
}
</style>

<span class='tooltip'><span class='tooltiptext'><script>
document.write("<script src=\"/feeds/posts/default/-/Your Label Post?max-results="+numposts4+"&orderby=published&alt=json-in-script&callback=showrecentposts4\"><\/script>");
</script>
</span></span>
<!DOCTYPE html>
<html>

<head>
<script type='text/javascript'>
//<![CDATA[

imgr = new Array();
imgr[0] = "http://2.bp.blogspot.com/-uitX7ROPtTU/Tyv-G4NA_uI/AAAAAAAAFBY/NcWLPVnYEnU/s1600/no+image.jpg";
showRandomImg = true;
aBold = true;
summaryPost = 170;
summaryPost4 = 160;
summaryTitle = 100;
numposts = 10;
numposts4 = 5;

function removeHtmlTag(strx,chop){
    var s = strx.split("<");
    for(var i=0;i<s.length;i++){
        if(s[i].indexOf(">")!=-1){
            s[i] = s[i].substring(s[i].indexOf(">")+1,s[i].length);
        }
    }
    s =  s.join("");
    s = s.substring(0,chop-1);
    return s;
}

function showrecentposts(json) {
    j = (showRandomImg) ? Math.floor((imgr.length+1)*Math.random()) : 0;
    img  = new Array();

      for (var i = 0; i < numposts; i++) {
        var entry = json.feed.entry[i];
        var posttitle = entry.title.$t;
        var pcm;
        var posturl;
        if (i == json.feed.entry.length) break;
        for (var k = 0; k < entry.link.length; k++) {
              if (entry.link[k].rel == 'alternate') {
                posturl = entry.link[k].href;
                break;
              }
        }
        
        for (var k = 0; k < entry.link.length; k++) {
              if (entry.link[k].rel == 'replies' && entry.link[k].type == 'text/html') {
                pcm = entry.link[k].title.split(" ")[0];
                break;
              }
        }
        
        if ("content" in entry) {
              var postcontent = entry.content.$t;}
        else
        if ("summary" in entry) {
              var postcontent = entry.summary.$t;}
        else var postcontent = "";
        
        postdate = entry.published.$t;
    
    if(j>imgr.length-1) j=0;
    img[i] = imgr[j];
    
    s = postcontent    ; a = s.indexOf("<img"); b = s.indexOf("src=\"",a); c = s.indexOf("\"",b+5); d = s.substr(b+5,c-b-5);

    if((a!=-1)&&(b!=-1)&&(c!=-1)&&(d!="")) img[i] = d;

    //cmtext = (text != 'no') ? '<i><font color="'+acolor+'">('+pcm+' '+text+')</font></i>' : '';


    var month = [1,2,3,4,5,6,7,8,9,10,11,12];
    var month2 = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];

    var day = postdate.split("-")[2].substring(0,2);
    var m = postdate.split("-")[1];
    var y = postdate.split("-")[0];

    for(var u2=0;u2<month.length;u2++){
        if(parseInt(m)==month[u2]) {
            m = month2[u2] ; break;
        }
    }

    var daystr = day+ ' ' + m + ' ' + y ;
    
    var trtd = '<li style="position:relative;"><div class="imgauto"><a href="'+posturl+'"><img width="200" height="150" class=" " src="'+img[i]+'"/></a></div><h3><a href="'+posturl+'">'+posttitle+'</a><p>'+daystr+' / '+pcm+' comments</p></h3></li>';                    
        document.write(trtd); 
             
              j++;
    }
    
}

function showrecentposts4(json) {
	j = (showRandomImg) ? Math.floor((imgr.length+1)*Math.random()) : 0;
	img  = new Array();
    if (numposts4 <= json.feed.entry.length) {
		maxpost = numposts4;
		}
	else
       {
	   maxpost=json.feed.entry.length;
	   }	
  	for (var i = 0; i < maxpost; i++) {
    	var entry = json.feed.entry[i];
    	var posttitle = entry.title.$t;
		var pcm;
    	var posturl;
    	if (i == json.feed.entry.length) break;
    	for (var k = 0; k < entry.link.length; k++) {
      		if (entry.link[k].rel == 'alternate') {
        		posturl = entry.link[k].href;
        		break;
      		}
    	}
		
		for (var k = 0; k < entry.link.length; k++) {
      		if (entry.link[k].rel == 'replies' && entry.link[k].type == 'text/html') {
        		pcm = entry.link[k].title.split(" ")[0];
        		break;
      		}
    	}
		
    	if ("content" in entry) {
      		var postcontent = entry.content.$t;}
    	else
    	if ("summary" in entry) {
      		var postcontent = entry.summary.$t;}
    	else var postcontent = "";
    	
    	postdate = entry.published.$t;
	
	if(j>imgr.length-1) j=0;
	img[i] = imgr[j];
	
	s = postcontent	; a = s.indexOf("<img"); b = s.indexOf("src=\"",a); c = s.indexOf("\"",b+5); d = s.substr(b+5,c-b-5);

	if((a!=-1)&&(b!=-1)&&(c!=-1)&&(d!="")) img[i] = d;

	//cmtext = (text != 'no') ? '<i><font color="'+acolor+'">('+pcm+' '+text+')</font></i>' : '';


	var month = [1,2,3,4,5,6,7,8,9,10,11,12];
	var month2 = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];

	var day = postdate.split("-")[2].substring(0,2);
	var m = postdate.split("-")[1];
	var y = postdate.split("-")[0];

	for(var u2=0;u2<month.length;u2++){
		if(parseInt(m)==month[u2]) {
			m = month2[u2] ; break;
		}
	}

	var daystr = day+ ' ' + m + ' ' + y ;
    pcm='<a href="'+posturl+'">'+pcm+' comments</a>';
	
 if (i==0) {
	var trtd = '<div class="entry-thumb"><a href="'+posturl+'"><img width="70" height="70" src="'+img[i]+'"/></a></div><h3 class="entry-title"><a href="'+posturl+'">'+posttitle+'</a></h3><div class="entry-meta"></div><div class="entry-excerpt"><p>'+removeHtmlTag(postcontent,summaryPost4)+'...</p></div>';
	document.write(trtd);
}
 if ((i>0)&&(i<maxpost))
    {
	var trtd = '<li class="catlist"><a href="'+posturl+'">'+posttitle+'</a></li>';
	document.write(trtd);
}
	j++;
}

}

 //]]>
</script>
</head>

<body>

您可以在harga lantai kayu

看到该演示