如何判断<script>标记是否加载失败

我dynamic地添加<script>标签到页面的<head> ,我想能够判断加载是否以某种方式失败 – 一个404,在加载的脚本中的脚本错误,无论如何。

在Firefox中,这个工作:

 var script_tag = document.createElement('script'); script_tag.setAttribute('type', 'text/javascript'); script_tag.setAttribute('src', 'http://fail.org/nonexistant.js'); script_tag.onerror = function() { alert("Loading failed!"); } document.getElementsByTagName('head')[0].appendChild(script_tag); 

但是,这在IE或Safari中不起作用。

有谁知道一种方法,使之在Firefox以外的其他浏览器的工作?

(我不认为需要在.js文件中添加特殊代码的解决scheme是一个很好的解决scheme,它不够灵活和不灵活)。

脚本标记没有错误事件。 你可以告诉它什么时候成功,并且假定在超时之后它没有被加载:

 <script type="text/javascript" onload="loaded=1" src="....js"></script> 

Erwinus的脚本很好用,但不是很清晰。 我冒昧地把它清理干净,破译了它正在做的事情。 我做了这些改变:

  • 有意义的variables名称
  • 使用prototype
  • require()使用参数variables
  • 没有alert()消息默认返回
  • 修复了一些语法错误和范围问题

再次感谢Erwinus,function本身就是现货。

 function ScriptLoader() { } ScriptLoader.prototype = { timer: function (times, // number of times to try delay, // delay per try delayMore, // extra delay per try (additional to delay) test, // called each try, timer stops if this returns true failure, // called on failure result // used internally, shouldn't be passed ) { var me = this; if (times == -1 || times > 0) { setTimeout(function () { result = (test()) ? 1 : 0; me.timer((result) ? 0 : (times > 0) ? --times : times, delay + ((delayMore) ? delayMore : 0), delayMore, test, failure, result); }, (result || delay < 0) ? 0.1 : delay); } else if (typeof failure == 'function') { setTimeout(failure, 1); } }, addEvent: function (el, eventName, eventFunc) { if (typeof el != 'object') { return false; } if (el.addEventListener) { el.addEventListener(eventName, eventFunc, false); return true; } if (el.attachEvent) { el.attachEvent("on" + eventName, eventFunc); return true; } return false; }, // add script to dom require: function (url, args) { var me = this; args = args || {}; var scriptTag = document.createElement('script'); var headTag = document.getElementsByTagName('head')[0]; if (!headTag) { return false; } setTimeout(function () { var f = (typeof args.success == 'function') ? args.success : function () { }; args.failure = (typeof args.failure == 'function') ? args.failure : function () { }; var fail = function () { if (!scriptTag.__es) { scriptTag.__es = true; scriptTag.id = 'failed'; args.failure(scriptTag); } }; scriptTag.onload = function () { scriptTag.id = 'loaded'; f(scriptTag); }; scriptTag.type = 'text/javascript'; scriptTag.async = (typeof args.async == 'boolean') ? args.async : false; scriptTag.charset = 'utf-8'; me.__es = false; me.addEvent(scriptTag, 'error', fail); // when supported // when error event is not supported fall back to timer me.timer(15, 1000, 0, function () { return (scriptTag.id == 'loaded'); }, function () { if (scriptTag.id != 'loaded') { fail(); } }); scriptTag.src = url; setTimeout(function () { try { headTag.appendChild(scriptTag); } catch (e) { fail(); } }, 1); }, (typeof args.delay == 'number') ? args.delay : 1); return true; } }; $(document).ready(function () { var loader = new ScriptLoader(); loader.require('resources/templates.js', { async: true, success: function () { alert('loaded'); }, failure: function () { alert('NOT loaded'); } }); }); 

如果你只关心html5浏览器,你可以使用错误事件(因为这只是为了处理错误,所以应该可以在下一代浏览器上支持这个)。

从规格:

如果src属性的值是空string,或者无法parsing,那么用户代理必须对任务进行排队以在元素上触发一个简单的事件error ,然后中止这些步骤。

如果加载导致错误(例如,DNS错误或HTTP 404错误),则执行脚本块必须包含在元素上触发一个名为error的简单事件。

这意味着您不必做任何容易出错的轮询,并可以将其与async和defer属性结合起来,以确保脚本不会阻止页面呈现:

即使指定了async属性,也可以指定defer属性,以使传统的仅支持延迟(而不是async)的Web浏览器回退到延迟行为,而不是默认的同步阻止行为。

更多关于http://www.w3.org/TR/html5/scripting-1.html#script

我知道这是一个古老的线程,但我得到了一个很好的解决scheme(我认为)。 它从我的一个类复制,处理所有的AJAX的东西。

当脚本无法加载时,它会设置一个error handling程序,但是当error handling程序不受支持时,它将返回到一个计时器,该计时器将在15秒内检查错误。

 function jsLoader() { var o = this; // simple unstopable repeat timer, when t=-1 means endless, when function f() returns true it can be stopped o.timer = function(t, i, d, f, fend, b) { if( t == -1 || t > 0 ) { setTimeout(function() { b=(f()) ? 1 : 0; o.timer((b) ? 0 : (t>0) ? --t : t, i+((d) ? d : 0), d, f, fend,b ); }, (b || i < 0) ? 0.1 : i); } else if(typeof fend == 'function') { setTimeout(fend, 1); } }; o.addEvent = function(el, eventName, eventFunc) { if(typeof el != 'object') { return false; } if(el.addEventListener) { el.addEventListener (eventName, eventFunc, false); return true; } if(el.attachEvent) { el.attachEvent("on" + eventName, eventFunc); return true; } return false; }; // add script to dom o.require = function(s, delay, baSync, fCallback, fErr) { var oo = document.createElement('script'), oHead = document.getElementsByTagName('head')[0]; if(!oHead) { return false; } setTimeout( function() { var f = (typeof fCallback == 'function') ? fCallback : function(){}; fErr = (typeof fErr == 'function') ? fErr : function(){ alert('require: Cannot load resource -'+s); }, fe = function(){ if(!oo.__es) { oo.__es = true; oo.id = 'failed'; fErr(oo); } }; oo.onload = function() { oo.id = 'loaded'; f(oo); }; oo.type = 'text/javascript'; oo.async = (typeof baSync == 'boolean') ? baSync : false; oo.charset = 'utf-8'; o.__es = false; o.addEvent( oo, 'error', fe ); // when supported // when error event is not supported fall back to timer o.timer(15, 1000, 0, function() { return (oo.id == 'loaded'); }, function(){ if(oo.id != 'loaded'){ fe(); } }); oo.src = s; setTimeout(function() { try{ oHead.appendChild(oo); }catch(e){ fe(); } },1); }, (typeof delay == 'number') ? delay : 1); return true; }; } $(document).ready( function() { var ol = new jsLoader(); ol.require('myscript.js', 800, true, function(){ alert('loaded'); }, function() { alert('NOT loaded'); }); }); 

要检查在var isExecuted = true;的JavaScript是否返回没有错误,你必须在http://fail.org/nonexistant.js添加一个variables,如var isExecuted = true; 然后在加载脚本标签时检查它是否存在。

但是,如果你只想检查没有404(意味着它存在)返回isLoaded ,你可以尝试一个isLoadedvariables…

 var isExecuted = false; var isLoaded = false; script_tag.onload = script_tag.onreadystatechange = function() { if(!this.readyState || this.readyState == "loaded" || this.readyState == "complete") { // script successfully loaded isLoaded = true; if(isExecuted) // no error } } 

这将涵盖两种情况。

我希望这不会被低估,因为在特殊情况下,这是解决问题的最可靠的方法。 只要服务器允许你使用CORS( http://en.wikipedia.org/wiki/Cross-origin_resource_sharing )获得一个Javascript资源,你就有了丰富的select。

使用XMLHttpRequest获取资源将适用于所有现代浏览器,包括IE。 既然你正在寻找加载的Javascript,你有Javascript提供给你的第一位。 您可以使用readyState( http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener )跟踪进度。 最后,一旦你收到文件的内容,你可以用eval()来执行它。 是的,我说eval – 因为安全性方面与正常加载脚本没有区别。 事实上,John Resig提出了一个类似的技术,它有更好的标签( http://ejohn.org/blog/degrading-script-tags/ )。

这个方法还可以让你从eval中分离出加载,并在eval发生之前和之后执行函数。 当并行加载脚本时,它们会相互之间非常有用,但一个接一个地评估它们是非常有用的 – 当您将标记放置在HTML中时,浏览器可以轻松地完成这些操作,但是不要让您在运行时使用Javascript来添加脚本。

对于加载脚本,CORS也比JSONP更可取( http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests )。 但是,如果您正在开发自己的第三方小部件以embedded到其他站点中,则实际上应将自己的域中的Javascript文件加载到您自己的iframe中(再次使用AJAX)

简而言之:

  1. 尝试查看是否可以使用AJAX GET加载资源

  2. 成功加载后使用eval

改善它:

  1. 检查正在发送的caching控制头

  2. 如果需要的话,研究否则cachinglocalStorage中的内容

  3. 查看Resig的“有辱人格的JavaScript”以获得更清晰的代码

  4. 查看require.js

这里是另一个基于JQuery的解决scheme,没有任何计时器:

 <script type="text/javascript"> function loadScript(url, onsuccess, onerror) { $.get(url) .done(function() { // File/url exists console.log("JS Loader: file exists, executing $.getScript "+url) $.getScript(url, function() { if (onsuccess) { console.log("JS Loader: Ok, loaded. Calling onsuccess() for " + url); onsuccess(); console.log("JS Loader: done with onsuccess() for " + url); } else { console.log("JS Loader: Ok, loaded, no onsuccess() callback " + url) } }); }).fail(function() { // File/url does not exist if (onerror) { console.error("JS Loader: probably 404 not found. Not calling $.getScript. Calling onerror() for " + url); onerror(); console.error("JS Loader: done with onerror() for " + url); } else { console.error("JS Loader: probably 404 not found. Not calling $.getScript. No onerror() callback " + url); } }); } </script> 

感谢: https : //stackoverflow.com/a/14691735/1243926

示例用法(来自JQuery getScript文档的原始示例):

 <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>jQuery.getScript demo</title> <style> .block { background-color: blue; width: 150px; height: 70px; margin: 10px; } </style> <script src="http://code.jquery.com/jquery-1.9.1.js"></script> </head> <body> <button id="go">&raquo; Run</button> <div class="block"></div> <script> function loadScript(url, onsuccess, onerror) { $.get(url) .done(function() { // File/url exists console.log("JS Loader: file exists, executing $.getScript "+url) $.getScript(url, function() { if (onsuccess) { console.log("JS Loader: Ok, loaded. Calling onsuccess() for " + url); onsuccess(); console.log("JS Loader: done with onsuccess() for " + url); } else { console.log("JS Loader: Ok, loaded, no onsuccess() callback " + url) } }); }).fail(function() { // File/url does not exist if (onerror) { console.error("JS Loader: probably 404 not found. Not calling $.getScript. Calling onerror() for " + url); onerror(); console.error("JS Loader: done with onerror() for " + url); } else { console.error("JS Loader: probably 404 not found. Not calling $.getScript. No onerror() callback " + url); } }); } loadScript("https://raw.github.com/jquery/jquery-color/master/jquery.color.js", function() { console.log("loaded jquery-color"); $( "#go" ).click(function() { $( ".block" ) .animate({ backgroundColor: "rgb(255, 180, 180)" }, 1000 ) .delay( 500 ) .animate({ backgroundColor: "olive" }, 1000 ) .delay( 500 ) .animate({ backgroundColor: "#00f" }, 1000 ); }); }, function() { console.error("Cannot load jquery-color"); }); </script> </body> </html> 

这个窍门对我很有帮助,但我承认这可能不是解决这个问题的最好方法。 而不是尝试这个,你应该看到为什么javascripts不加载。 尝试在您的服务器上保留脚本的本地副本等,或与您尝试下载脚本的第三方供应商联系。

无论如何,所以这里是解决方法:1)初始化一个variables为false 2)将其设置为true时,JavaScript加载(使用onload属性)3)检查是否variables是真或假一旦HTML体已经加载

 <html> <head> <script> var scriptLoaded = false; function checkScriptLoaded() { if (scriptLoaded) { // do something here } else { // do something else here! } } </script> <script src="http://some-external-script.js" onload="scriptLoaded=true;" /> </head> <body onload="checkScriptLoaded()"> <p>My Test Page!</p> </body> </html> 

那么,我能想到做你想做的一切的唯一方法是非常难看的。 首先执行一个AJAX调用来检索Javascript文件的内容。 完成后,您可以检查状态码以确定是否成功。 然后从xhr对象中获取responseText,并将其封装在try / catch中,dynamic创build脚本标记,对于IE,您可以将脚本标记的text属性设置为JS文本,在所有其他浏览器中,您应该能够将带有内容的文本节点附加到脚本标记。 如果有任何代码需要脚本标记实际包含文件的src位置,这将无法正常工作,但在大多数情况下应该没问题。 丑,但会工作。 你可以看看我的快速和肮脏的例子: http : //pastie.org/829775

它在Safari中不起作用的原因是因为您正在使用属性语法。 这将工作正常,虽然:

 script_tag.addEventListener('error', function(){/*...*/}, true); 

除IE外。

如果你想检查脚本执行成功,只需使用该脚本设置一个variables,并检查它是否被设置在外部代码。

build议设置一个超时,然后在超时后假设加载失败。

 setTimeout(fireCustomOnerror, 4000); 

这种方法的问题是假设是基于偶然的。 超时过期后,请求仍处于待处理状态。 即使在编程人员假定加载不会发生之后,也可以加载对待处理脚本的请求。

如果请求可以被取消,那么程序可能会等待一段时间,然后取消请求。

你可以在java脚本文件中join一个函数,如check(){var report; report = True}然后运行这个函数,如果函数没有运行或者没有响应可能脚本没有加载其他的我认为脚本不是可以使用 。 onload属性也是有用的。

我工作干净的解决scheme(2017)

 function loaderScript(scriptUrl){ return new Promise(function (res, rej) { let script = document.createElement('script'); script.src = scriptUrl; script.type = 'text/javascript'; script.onError = rej; script.async = true; script.onload = res; script.addEventListener('error',rej); script.addEventListener('load',res); document.head.appendChild(script); }) } 

我不知道如何得到这个工作,但如果你想dynamic加载JavaScript,我知道用jQuery加载JavaScript将运行该脚本,或者只是加载JavaScript的任何AJAXfunction和eval()它应该工作。