document.createElement ( "script") 동기식
.js
파일을 동 기적 으로 호출 한 다음 즉시 사용할 수 있습니까?
<script type="text/javascript">
var head = document.getElementsByTagName('head').item(0);
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', 'http://mysite/my.js');
head.appendChild(script);
myFunction(); // Fails because it hasn't loaded from my.js yet.
window.onload = function() {
// Works most of the time but not all of the time.
// Especially if my.js injects another script that contains myFunction().
myFunction();
};
</script>
이것은 간단합니다. 내 구현에서 createElement 물건은 함수에 있습니다. 컨트롤을 반환하기 전에 특정 변수가 인스턴스화되었는지 확인할 수있는 함수에 무언가를 추가하는 것에 대해 생각했습니다. 그러나 내가 제어 할 수없는 다른 사이트의 js를 포함 할 때해야 할 일에 대한 문제가 여전히 있습니다.
생각?
편집하다:
나는 무슨 일이 일어나고 있는지에 대한 좋은 설명을 제공하기 때문에 지금은 최고의 답변을 수락했습니다. 그러나 누군가 이것을 개선하는 방법에 대한 제안이 있다면 나는 그들에게 열려 있습니다. 제가하고 싶은 일의 예가 있습니다.
// Include() is a custom function to import js.
Include('my1.js');
Include('my2.js');
myFunc1('blarg');
myFunc2('bleet');
내부를 너무 많이 알지 않고 "이 모듈을 사용하고 싶습니다. 이제 코드를 사용할 것입니다."라고 말할 수 있기를 바랍니다.
<script>
"onload"핸들러를 사용하여 요소를 만들 수 있으며 , 이는 브라우저에서 스크립트가로드되고 평가 될 때 호출됩니다.
var script = document.createElement('script');
script.onload = function() {
alert("Script loaded and ready");
};
script.src = "http://whatever.com/the/script.js";
document.getElementsByTagName('head')[0].appendChild(script);
동 기적으로 할 수는 없습니다.
편집 — IE가로 <script>
드 / 평가되는 태그에 대해 "로드"이벤트를 발생시키지 않는다는 점이 지적되었습니다 . 따라서 다음으로 할 일은 XMLHttpRequest를 사용하여 스크립트를 가져온 다음 eval()
직접 가져 오는 것입니다. (또는 <script>
추가 한 태그에 텍스트를 넣는다 고 생각 합니다. 실행 환경은 eval()
로컬 범위의 영향을 받기 때문에 원하는 작업을 수행 할 필요는 없습니다.)
편집 — 2013 년 초부터 Requirejs 와 같은보다 강력한 스크립트 로딩 도구를 찾는 것이 좋습니다 . 걱정해야 할 특별한 경우가 많이 있습니다. 정말 간단한 상황을 위해 현재 Modernizr에 내장 된 yepnope 가 있습니다 .
이것은 예쁘지는 않지만 작동합니다.
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"></script>');
</script>
<script type="text/javascript">
functionFromOther();
</script>
또는
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"></script>');
window.onload = function() {
functionFromOther();
};
</script>
스크립트는 별도의 <script>
태그 또는 앞에 포함되어야합니다 window.onload()
.
작동하지 않습니다.
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"></script>');
functionFromOther(); // Error
</script>
Pointy가 한 것처럼 노드를 만들 때도 똑같이 할 수 있지만 FF에서만 가능합니다. 스크립트가 다른 브라우저에서 언제 준비되는지 보장 할 수 없습니다.
XML 순수 주의자이기 때문에 나는 이것을 정말로 싫어한다. 하지만 예상대로 작동합니다. 당신은 document.write()
그들을 볼 필요가 없도록 그 추악한들을 쉽게 감쌀 수 있습니다 . 테스트를 수행하고 노드를 생성하고 추가 한 다음 폴백 할 수도 document.write()
있습니다.
이 작업은 늦었지만이 작업을 원하는 사람이 나중에 참조 할 수 있도록 다음을 사용할 수 있습니다.
function require(file,callback){
var head=document.getElementsByTagName("head")[0];
var script=document.createElement('script');
script.src=file;
script.type='text/javascript';
//real browsers
script.onload=callback;
//Internet explorer
script.onreadystatechange = function() {
if (this.readyState == 'complete') {
callback();
}
}
head.appendChild(script);
}
얼마 전에 짧은 블로그 게시물을 작성했습니다. http://crlog.info/2011/10/06/dynamically-requireinclude-a-javascript-file-into-a-page-and-be-notified-when-its -짐을 실은/
비동기 프로그래밍은 요청의 결과가 요청 문을 따르는 대신 함수에 캡슐화되기 때문에 약간 더 복잡 합니다. 그러나 사용자가 경험 하는 실시간 동작 은 느린 서버 나 느린 네트워크를 보지 않기 때문에 브라우저가 마치 충돌 한 것처럼 작동 하게 하기 때문에 훨씬 더 좋을 수 있습니다 . 동기 프로그래밍은 무례 하며 사람이 사용하는 응용 프로그램에 사용해서는 안됩니다 .
Douglas Crockford ( YUI 블로그 )
좋아요, 좌석을 버클로 묶으세요. 타는 것이 울퉁불퉁 할 테니까요. 점점 더 많은 사람들이 자바 스크립트를 통해 스크립트를 동적으로로드하는 것에 대해 묻고 있는데, 이는 뜨거운 주제 인 것 같습니다.
이것이 인기를 얻은 주된 이유는 다음과 같습니다.
- 클라이언트 측 모듈성
- 더 쉬운 종속성 관리
- 오류 처리
- 성능 이점
모듈성에 관하여 : 클라이언트 측 종속성 관리는 클라이언트 측에서 바로 처리되어야한다는 것은 분명합니다. 특정 개체, 모듈 또는 라이브러리가 필요한 경우 요청하고 동적으로로드합니다.
오류 처리 : 리소스가 실패하더라도 영향을받는 스크립트에 의존하는 부분 만 차단하거나 약간의 지연을두고 다시 시도 할 수 있습니다.
성능 은 웹 사이트 간의 경쟁 우위가되었으며 이제 검색 순위 요소입니다. 동적 스크립트가 할 수있는 것은 브라우저가 스크립트를 처리하는 방법의 기본 차단 방식과는 반대로 비동기 동작을 모방하는 것입니다. 스크립트는 다른 리소스 를 차단 하고 스크립트 는 HTML 문서의 추가 구문 분석을 차단 하며 스크립트 는 UI를 차단 합니다. 이제 동적 스크립트 태그 및 브라우저 간 대안을 사용하여 실제 비동기 요청을 수행하고 사용 가능한 경우에만 종속 코드를 실행할 수 있습니다. 스크립트는 다른 리소스와도 병렬로로드되며 렌더링은 완벽합니다.
일부 사람들이 동기식 스크립팅을 고수하는 이유는 익숙해지기 때문입니다. 그들은 그것이 기본 방법이라고 생각하고 더 쉬운 방법이며 일부는 그것이 유일한 방법이라고 생각할 수도 있습니다.
그러나 애플리케이션 디자인과 관련하여 이것이 결정되어야 할 때 우리가주의해야 할 유일한 것은 최종 사용자 경험 입니다. 그리고이 영역에서 비동기식은 이길 수 없습니다. 사용자는 즉각적인 응답을 받고 (또는 약속을 말하며) 약속은 항상없는 것보다 낫습니다. 빈 화면은 사람들을 두렵게합니다. 개발자는 인지 된 성능 을 향상시키기 위해 게으르지 않아야 합니다 .
그리고 마지막으로 더러운면에 대한 몇 마디. 브라우저에서 작동하도록하려면 다음을 수행해야합니다.
- 비동기 적으로 생각하는 법 배우기
- 모듈 식으로 코드 구성
- 오류 및 엣지 케이스를 잘 처리하도록 코드 구성
- 점진적으로 향상
- 항상 적절한 양의 피드백을 처리합니다.
위의 답변은 저를 올바른 방향으로 안내했습니다. 다음은 내가 일한 것의 일반적인 버전입니다.
var script = document.createElement('script');
script.src = 'http://' + location.hostname + '/module';
script.addEventListener('load', postLoadFunction);
document.head.appendChild(script);
function postLoadFunction() {
// add module dependent code here
}
이것은 동적 스크립트 로딩에 대한 적절한 개요처럼 보입니다 : http://unixpapa.com/js/dyna.html
이 질문에 대한 기존 답변 (및 다른 stackoverflow 스레드 에서이 질문의 변형)에 다음과 같은 문제가 있습니다.
- 로드 된 코드는 디버깅 할 수 없습니다.
- 많은 솔루션에서 실제로 차단하는 대신로드가 완료된 시점을 알기 위해 콜백이 필요했습니다. 즉,로드 된 (즉,로드하는) 코드를 즉시 호출하면 실행 오류가 발생합니다.
또는 약간 더 정확하게 :
- 로드 된 코드 중 어느 것도 디버깅 할 수 없었습니다 (HTML 스크립트 태그 블록을 제외하고, 솔루션이 dom에 스크립트 요소를 추가 한 경우에만 가능하며 개별적으로 볼 수있는 스크립트가 아닌 경우). =>로드해야하는 스크립트 수 ( 및 디버그), 이것은 용납 할 수 없습니다.
- 'onreadystatechange'또는 'onload'이벤트를 사용하는 솔루션을 차단하지 못했습니다. 코드가 원래 'require ([filename,'dojo / domReady ']);'를 사용하여 동적 스크립트를 동 기적으로로드했기 때문에 큰 문제였습니다. 도장을 벗기고있었습니다.
반환하기 전에 스크립트를로드하고 디버거에서 모든 스크립트에 올바르게 액세스 할 수있는 최종 솔루션 (최소한 Chrome의 경우)은 다음과 같습니다.
경고 : 다음 코드는 '개발'모드에서만 사용되어야합니다. ( '릴리스'모드의 경우 동적 스크립트로드없이 또는 최소한 eval없이 사전 패키징 및 축소를 권장합니다.)
//Code User TODO: you must create and set your own 'noEval' variable
require = function require(inFileName)
{
var aRequest
,aScript
,aScriptSource
;
//setup the full relative filename
inFileName =
window.location.protocol + '//'
+ window.location.host + '/'
+ inFileName;
//synchronously get the code
aRequest = new XMLHttpRequest();
aRequest.open('GET', inFileName, false);
aRequest.send();
//set the returned script text while adding special comment to auto include in debugger source listing:
aScriptSource = aRequest.responseText + '\n////# sourceURL=' + inFileName + '\n';
if(noEval)//<== **TODO: Provide + set condition variable yourself!!!!**
{
//create a dom element to hold the code
aScript = document.createElement('script');
aScript.type = 'text/javascript';
//set the script tag text, including the debugger id at the end!!
aScript.text = aScriptSource;
//append the code to the dom
document.getElementsByTagName('body')[0].appendChild(aScript);
}
else
{
eval(aScriptSource);
}
};
function include(file){
return new Promise(function(resolve, reject){
var script = document.createElement('script');
script.src = file;
script.type ='text/javascript';
script.defer = true;
document.getElementsByTagName('head').item(0).appendChild(script);
script.onload = function(){
resolve()
}
script.onerror = function(){
reject()
}
})
/*I HAVE MODIFIED THIS TO BE PROMISE-BASED
HOW TO USE THIS FUNCTION
include('js/somefile.js').then(function(){
console.log('loaded');
},function(){
console.log('not loaded');
})
*/
}
I am used to having multiple .js files on my web site that depend one on another. To load them and ensure that the dependencies are evaluated in the right order, I have written a function that loads all the files and then, once they are all received, eval()
them. The main drawback is that since this does not work with CDN. For such libraries (e.g., jQuery) it is better to include them statically. Note that inserting script nodes in the HTML dynamically won't guarantee that scripts are evaluated in the right order, at least not in Chrome (this was the major reason for writing this function).
function xhrs(reqs) {
var requests = [] , count = [] , callback ;
callback = function (r,c,i) {
return function () {
if ( this.readyState == 4 ) {
if (this.status != 200 ) {
r[i]['resp']="" ;
}
else {
r[i]['resp']= this.responseText ;
}
c[0] = c[0] - 1 ;
if ( c[0] == 0 ) {
for ( var j = 0 ; j < r.length ; j++ ) {
eval(r[j]['resp']) ;
}
}
}
}
} ;
if ( Object.prototype.toString.call( reqs ) === '[object Array]' ) {
requests.length = reqs.length ;
}
else {
requests.length = 1 ;
reqs = [].concat(reqs);
}
count[0] = requests.length ;
for ( var i = 0 ; i < requests.length ; i++ ) {
requests[i] = {} ;
requests[i]['xhr'] = new XMLHttpRequest () ;
requests[i]['xhr'].open('GET', reqs[i]) ;
requests[i]['xhr'].onreadystatechange = callback(requests,count,i) ;
requests[i]['xhr'].send(null);
}
}
I haven't figured out how to make references to the same value without creating an array (for count). Otherwise I think it is self-explanatory (when everything is loaded, eval()
every file in the order given, otherwise just store the response).
Usage example:
xhrs( [
root + '/global.js' ,
window.location.href + 'config.js' ,
root + '/js/lib/details.polyfill.min.js',
root + '/js/scripts/address.js' ,
root + '/js/scripts/tableofcontents.js'
]) ;
Ironically, I have what you want, but want something closer to what you had.
I am loading things in dynamically and asynchronously, but with an load
callback like so (using dojo and xmlhtpprequest)
dojo.xhrGet({
url: 'getCode.php',
handleAs: "javascript",
content : {
module : 'my.js'
},
load: function() {
myFunc1('blarg');
},
error: function(errorMessage) {
console.error(errorMessage);
}
});
For a more detailed explanation, see here
The problem is that somewhere along the line the code gets evaled, and if there's anything wrong with your code, the console.error(errorMessage);
statement will indicate the line where eval()
is, not the actual error. This is SUCH a big problem that I am actually trying to convert back to <script>
statements (see here.
참고URL : https://stackoverflow.com/questions/3248384/document-createelementscript-synchronously
'Nice programing' 카테고리의 다른 글
루트에서 하위 디렉터리로 IIS7 URL 리디렉션 (0) | 2020.10.28 |
---|---|
파이썬에서 신호에 잡음 추가 (0) | 2020.10.28 |
CodeIgniter-한 행만 반환합니까? (0) | 2020.10.28 |
SQL에서 난수로 열을 어떻게 채울 수 있습니까? (0) | 2020.10.28 |
콘텐츠 유형 text / xml; (0) | 2020.10.28 |