<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 파일 내에 특수 코드를 배치해야하는 솔루션이 좋은 것이라고 생각하지 않습니다. 우아하지 않고 융통성이 없습니다.)
답변
스크립트 태그에 대한 오류 이벤트가 없습니다. 성공한 시점을 알 수 있으며 시간 초과 후로드되지 않았다고 가정 할 수 있습니다.
<script type="text/javascript" onload="loaded=1" src="....js"></script>
답변
html5 브라우저 만 신경 쓰는 경우 오류 이벤트를 사용할 수 있습니다 (오류 처리 전용이므로 KISS IMHO의 차세대 브라우저에서만 지원하는 것이 좋습니다).
사양에서 :
src 속성의 값이 빈 문자열이거나 확인할 수없는 경우 사용자 에이전트는 작업을 대기열에 넣어 error 라는 간단한 이벤트를 발생시켜야합니다. 요소에서 이러한 단계를 중단해야합니다.
~
로드로 인해 오류 (예 : DNS 오류 또는 HTTP 404 오류)가 발생한 경우 스크립트 블록 실행은 요소에서 error라는 간단한 이벤트를 발생시키는 것으로 구성되어야합니다.
즉, 오류가 발생하기 쉬운 폴링을 수행 할 필요가 없으며이를 async 및 defer 속성과 결합하여 스크립트가 페이지 렌더링을 차단하지 않도록 할 수 있습니다.
지연 (비동기 아님) 만 지원하는 레거시 웹 브라우저가 기본값 인 동기 차단 동작 대신 지연 동작으로 폴백하도록 비동기 특성이 지정된 경우에도 defer 특성을 지정할 수 있습니다.
http://www.w3.org/TR/html5/scripting-1.html#script 에 대한 추가 정보
답변
Erwinus의 스크립트는 훌륭하게 작동하지만 명확하게 코딩되지 않았습니다. 나는 그것을 정리하고 그것이 무엇을하는지 해독 할 자유를 얻었다. 다음과 같이 변경했습니다.
- 의미있는 변수 이름
- 의 사용
prototype
. require()
인수 변수를 사용합니다.- 아니
alert()
기본적으로 반환되는 메시지가 - 몇 가지 구문 오류 및 범위 문제를 수정했습니다.
다시 Erwinus 덕분에 기능 자체가 자리를 잡았습니다.
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');
}
});
});
답변
마이 워킹 클린 솔루션 (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);
})
}
Martin이 지적했듯이 다음과 같이 사용했습니다.
const event = loaderScript("myscript.js")
.then(() => { console.log("loaded"); })
.catch(() => { console.log("error"); });
또는
try{
await loaderScript("myscript.js")
console.log("loaded");
}catch{
console.log("error");
}
답변
나는 이것이 오래된 스레드라는 것을 알고 있지만 당신에게 좋은 해결책을 얻었습니다 (제 생각에). 모든 AJAX 항목을 처리하는 내 클래스에서 복사되었습니다.
스크립트를로드 할 수없는 경우 오류 핸들러를 설정하지만 오류 핸들러가 지원되지 않으면 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');
});
});
답변
자바 스크립트가 nonexistant.js
오류를 반환하지 않았 는지 확인하려면 다음 http://fail.org/nonexistant.js
과 같이 변수를 추가해야합니다.var isExecuted = true;
다음 스크립트 태그가로드 될 때 존재하는지 확인해야합니다.
그러나 nonexistant.js
404 (존재한다는 의미)없이 반환 된 것을 확인하고 싶다면 isLoaded
변수로 시도 할 수 있습니다 …
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 )를 사용하여 자바 스크립트 리소스를 얻을 수 있도록 허용 할 때마다 다양한 옵션을 사용할 수 있습니다.
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/ ).
이 메서드를 사용하면 평가에서로드를 분리하고 평가가 발생하기 전후에 함수를 실행할 수 있습니다. 스크립트를 병렬로로드하지만 차례로 평가할 때 매우 유용합니다. HTML에 태그를 배치하면 브라우저가 쉽게 할 수 있지만 자바 스크립트를 사용하여 런타임에 스크립트를 추가하는 것은 허용하지 않습니다.
CORS는 스크립트를로드 할 때 JSONP보다 선호됩니다 ( http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests ). 그러나 다른 사이트에 임베드 할 자체 타사 위젯을 개발하는 경우 실제로 자체 iframe의 자체 도메인에서 Javascript 파일을로드해야합니다 (다시 AJAX 사용).
요컨대 :
-
AJAX GET을 사용하여 리소스를로드 할 수 있는지 확인하십시오.
-
성공적으로로드 된 후 eval 사용
개선하려면 :
-
전송되는 캐시 제어 헤더를 확인하십시오.
-
필요한 경우 localStorage의 콘텐츠 캐싱을 살펴보십시오.
-
더 깨끗한 코드를 위해 Resig의 “degrading javascript”를 확인하십시오.
-
require.js 확인
