[javascript] 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를 차단 합니다. 이제 동적 스크립트 태그 및 브라우저 간 대안을 사용하여 실제 비동기 요청을 수행하고 사용 가능한 경우에만 종속 코드를 실행할 수 있습니다. 스크립트는 다른 리소스와도 병렬로로드되며 렌더링은 완벽합니다.

일부 사람들이 동기식 스크립팅을 고수하는 이유는 익숙해지기 때문입니다. 그들은 그것이 기본 방법이라고 생각하고 더 쉬운 방법이며 일부는 그것이 유일한 방법이라고 생각할 수도 있습니다.

그러나 애플리케이션의 디자인과 관련하여 이것이 결정되어야 할 때 우리가주의해야 할 유일한 것은 최종 사용자 경험 입니다. 그리고이 영역에서 비동기식은 이길 수 없습니다. 사용자는 즉각적인 응답을 받고 (또는 약속을 말하며) 약속은 항상없는 것보다 낫습니다. 빈 화면은 사람들을 두렵게합니다. 개발자는 인지 된 성능 을 향상시키기 위해 게으르지 않아야 합니다 .

그리고 마지막으로 더러운면에 대한 몇 마디. 브라우저에서 작동하도록하려면 다음을 수행해야합니다.

  1. 비동기 적으로 생각하는 법 배우기
  2. 모듈 식으로 코드 구성
  3. 오류와 엣지 케이스를 잘 처리하도록 코드 구성
  4. 점진적으로 향상
  5. 항상 적절한 양의 피드백을 처리합니다.


답변

위의 답변은 저를 올바른 방향으로 안내했습니다. 다음은 내가 일한 것의 일반적인 버전입니다.

  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
  }


답변

이 질문에 대한 기존 답변 (및 다른 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');
  })
  */
}