비동기 적으로 스크립트로드


125

JQuery의 여러 플러그인, 사용자 정의 위젯 및 기타 라이브러리를 사용하고 있습니다. 결과적으로 여러 .js 및 .css 파일이 있습니다. 로드하는 데 시간이 좀 걸리기 때문에 내 사이트에 대한 로더를 만들어야합니다. 다음을 모두 가져 오기 전에 로더를 표시 할 수 있으면 좋을 것입니다.

<script type="text/javascript" src="js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="js/myFunctions.js"></script>
<link type="text/css" href="css/main.css" rel="stylesheet" />
... 
....
 etc

JavaScript 라이브러리를 비동기 적으로 가져올 수있는 몇 가지 자습서를 찾았습니다. 예를 들어 다음과 같이 할 수 있습니다.

  (function () {
        var s = document.createElement('script');
        s.type = 'text/javascript';
        s.async = true;
        s.src = 'js/jquery-ui-1.8.16.custom.min.js';
        var x = document.getElementsByTagName('script')[0];
        x.parentNode.insertBefore(s, x);
    })();

어떤 이유로 내 모든 파일에 대해 동일한 작업을 수행하면 페이지가 작동하지 않습니다. 문제가있는 곳을 찾으려고 오랫동안 노력했지만 찾을 수 없습니다. 처음에는 일부 자바 스크립트 기능이 다른 기능에 의존하기 때문일 것이라고 생각했습니다. 그러나 하나가 완료되었을 때 시간 초과 기능을 사용하여 올바른 순서로로드했습니다. 다음 작업을 진행했는데 페이지가 여전히 이상하게 작동합니다. 예를 들어 링크 등을 클릭 할 수 없습니다. 애니메이션은 여전히 ​​작동합니다.

어쨌든

제가 생각한 것은 다음과 같습니다. 브라우저에는 캐시가 있기 때문에 처음으로 페이지를로드하는 데 시간이 오래 걸리고 다음 번에는 빠릅니다. 그래서 제가 생각하는 것은 index.html 페이지를이 모든 파일을 비동기 적으로로드하는 페이지로 바꾸는 것입니다. ajax가 모든 파일을로드하면 내가 사용할 페이지로 리디렉션됩니다. 해당 페이지를 사용할 때 파일이 브라우저의 캐시에 포함되어야하므로로드하는 데 오래 걸리지 않아야합니다. 내 색인 페이지 (.js 및 .css 파일이 비동기 적으로로드되는 페이지)에서 오류가 발생해도 상관 없습니다. 완료되면 로더를 표시하고 페이지를 리디렉션합니다.

이 아이디어가 좋은 대안입니까? 또는 비동기 메서드를 계속 구현해야합니까?


편집하다

모든 비동기를로드하는 방법은 다음과 같습니다.

importScripts();

function importScripts()
{
    //import: jquery-ui-1.8.16.custom.min.js
    getContent("js/jquery-1.6.2.min.js",function (code) {
                var s = document.createElement('script');
                s.type = 'text/javascript';
                //s.async = true;
                s.innerHTML=code;
                var x = document.getElementsByTagName('script')[0];
                x.parentNode.insertBefore(s, x);
                setTimeout(insertNext1,1);
            });


    //import: jquery-ui-1.8.16.custom.min.js
    function insertNext1()
    {
        getContent("js/jquery-ui-1.8.16.custom.min.js",function (code) {
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext2,1);
                });
    }

    //import: jquery-ui-1.8.16.custom.css
    function insertNext2()
    {

        getContent("css/custom-theme/jquery-ui-1.8.16.custom.css",function (code) {
                    var s = document.createElement('link');
                    s.type = 'text/css';
                    s.rel ="stylesheet";
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext3,1);
                });
    }

    //import: main.css
    function insertNext3()
    {

        getContent("css/main.css",function (code) {
                    var s = document.createElement('link');
                    s.type = 'text/css';
                    s.rel ="stylesheet";
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext4,1);
                });
    }

    //import: jquery.imgpreload.min.js
    function insertNext4()
    {
        getContent("js/farinspace/jquery.imgpreload.min.js",function (code) {
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext5,1);
                });
    }


    //import: marquee.js
    function insertNext5()
    {
        getContent("js/marquee.js",function (code) {
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext6,1);
                });
    }


    //import: marquee.css
    function insertNext6()
    {

        getContent("css/marquee.css",function (code) {
                    var s = document.createElement('link');
                    s.type = 'text/css';
                    s.rel ="stylesheet";
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext,1);
                });
    }



    function insertNext()
    {
        setTimeout(pageReadyMan,10);        
    }
}


// get the content of url and pass that content to specified function
function getContent( url, callBackFunction )
{
     // attempt to create the XMLHttpRequest and make the request
     try
     {
        var asyncRequest; // variable to hold XMLHttpRequest object
        asyncRequest = new XMLHttpRequest(); // create request object

        // register event handler
        asyncRequest.onreadystatechange = function(){
            stateChange(asyncRequest, callBackFunction);
        } 
        asyncRequest.open( 'GET', url, true ); // prepare the request
        asyncRequest.send( null ); // send the request
     } // end try
     catch ( exception )
     {
        alert( 'Request failed.' );
     } // end catch
} // end function getContent

// call function whith content when ready
function stateChange(asyncRequest, callBackFunction)
{
     if ( asyncRequest.readyState == 4 && asyncRequest.status == 200 )
     {
           callBackFunction(asyncRequest.responseText);
     } // end if
} // end function stateChange

그리고 이상한 부분은 모든 스타일의 작업과 모든 자바 스크립트 함수입니다. 그래도 페이지가 멈췄습니다 ...

답변:


176

비동기 로딩을위한 몇 가지 솔루션 :

//this function will work cross-browser for loading scripts asynchronously
function loadScript(src, callback)
{
  var s,
      r,
      t;
  r = false;
  s = document.createElement('script');
  s.type = 'text/javascript';
  s.src = src;
  s.onload = s.onreadystatechange = function() {
    //console.log( this.readyState ); //uncomment this line to see which ready states are called.
    if ( !r && (!this.readyState || this.readyState == 'complete') )
    {
      r = true;
      callback();
    }
  };
  t = document.getElementsByTagName('script')[0];
  t.parentNode.insertBefore(s, t);
}

페이지에 이미 jQuery가있는 경우 다음을 사용하십시오.

$.getScript(url, successCallback)*

또한 문서가로드되기 전에 스크립트가로드 / 실행될 document.ready수 있습니다. 즉, 이벤트가 요소에 바인딩 될 수 있기 전에 기다려야합니다 .

코드를 보지 않고는 문제가 무엇인지 구체적으로 말할 수 없습니다.

가장 간단한 해결책은 모든 스크립트를 페이지 하단에 인라인으로 유지하는 것입니다. 이렇게하면 실행 중에 HTML 콘텐츠로드를 차단하지 않습니다. 또한 필요한 각 스크립트를 비동기 적으로로드해야하는 문제를 방지합니다.

어떤 종류의 더 큰 스크립트를 필요로하는 항상 사용되지 않는 특히 멋진 상호 작용이있는 경우 필요할 때까지 특정 스크립트를로드하지 않는 것이 유용 할 수 있습니다 (지연로드).

*로 로드 된 스크립트 $.getScript는 캐시되지 않을 가능성이 높습니다.


Promise객체 와 같은 최신 기능을 사용할 수있는 사람이라면 누구나 loadScript기능이 훨씬 간단 해졌습니다.

function loadScript(src) {
    return new Promise(function (resolve, reject) {
        var s;
        s = document.createElement('script');
        s.src = src;
        s.onload = resolve;
        s.onerror = reject;
        document.head.appendChild(s);
    });
}

callback반환 된 promise가 콜백을 처리하므로이 버전은 더 이상 인수를 허용하지 않습니다 . 이전에는이었을 loadScript(src, callback)loadScript(src).then(callback)입니다.

이것은 실패를 감지하고 처리 할 수 ​​있다는 추가 보너스가 있습니다.

loadScript(cdnSource)
    .catch(loadScript.bind(null, localSource))
    .then(successCallback, failureCallback);

... 그리고 CDN 중단을 우아하게 처리합니다.


나는 그것을 시도하기 시작합니다. 그러나 페이지를 다른 페이지로 리디렉션 할 때 해당 스크립트를 다른 페이지에로드하고 해당 페이지에 동일한 스크립트가있는 경우로드하는 데 시간이 걸리지 않아야합니다. 캐시에 있어야 하죠? 그래서 대신 그 기술을 구현해야하지 않습니까?
Tono Nam

1
본문 대신 head 태그에 자식을 변경하고 추가했습니다 ... ..var x = document.getElementsByTagName ( 'head') [0]; x.appendChild (s);
Tono Nam

1
@TonoNam, 그냥 사용할 수 document.head.appendChild있지만 스크립트를 추가하는 데 몇 가지 틈새 문제가 있습니다 <head>. 스크립트가로드 및 실행되는 것을 방해하는 것은 없습니다.
zzzzBov

1
나는 t.parentNode.insertBefore (t.parent와 반대)를 사용해야했습니다.
Phil LaNasa

1
@MuhammadUmer, document.write문서가로드되기 전에 추가 스크립트 태그를 작성하는 경우 스크립트는 페이지로드의 일부로 동 기적으로 실행되며 자체적으로 비동기 콜백 동작을 포함하지 않습니다. 스크립트 요소를 만들어 페이지에 추가하는 경우 이벤트 리스너를 추가하여 비동기식으로 트리거 할 수 있습니다. tl; dr : JS로 스크립트를로드하는 방법에 따라 다릅니다.
zzzzBov 2014 년

33

HTML5의 새로운 'async'속성이 트릭을 수행합니다. IE에 관심이 있다면 대부분의 브라우저에서 '지연'도 지원됩니다.

async-HTML

<script async src="siteScript.js" onload="myInit()"></script>

지연-HTML

<script defer src="siteScript.js" onload="myInit()"></script>

새 애드 센스 광고 단위 코드를 분석하는 동안 속성과 검색 결과를 발견했습니다. http://davidwalsh.name/html5-async


stackoverflow.com/questions/2774373/… 을 읽은 후 내 이해 에서 asyn은로드 용이 아니라 포함 된 javascript를 실행할시기를 결정하기위한 것입니다.
JackDev 2013 년

9
defer 속성은 문서가로드되고 구문 분석되고 조작 할 준비가 될 때까지 브라우저가 스크립트 실행을 연기하도록합니다. async 속성은 브라우저가 가능한 한 빨리 스크립트를 실행하도록하지만 스크립트가 다운로드되는 동안 문서 구문 분석을 차단하지 않도록합니다
shuseel

1
"asyn은로드 용이 아니라 포함 된 javascript를 실행할시기를 결정하기위한 것입니다."이것은 모순되지 않습니다. 모든 경우에 브라우저는 최대한 빨리 스크립트로드를 시작합니다. 그러나 없이 async 또는 defer그것을로드하는 동안 렌더링을 차단합니다. 설정 async은 스크립트를 최대한 빨리 차단하고 실행하지 않도록 지시합니다. 설정 defer은 차단하지 않도록 지시하지만 페이지가 완료 될 때까지 스크립트 실행을 기다립니다 . 일반적으로 스크립트에 종속성 (예 : jQuery)이없는 한 최대한 빨리 스크립트를 실행하는 것은 문제가되지 않습니다. 한 스크립트에 다른 스크립트에 대한 종속성이 있으면를 사용 onLoad하여 기다리십시오.
Stijn de Witt

@StijndeWitt 비동기도 지연도 지정되지 않으면 어떻게됩니까?
Mohammed Shareef C 2016

@MohammedShareefC 둘 다 지정하지 않으면 동기화 동작과 매우 유사한 결과가 나타납니다. 브라우저는 스크립트를 다운로드하고 실행하는 동안 추가 처리를 차단합니다. 따라서 사실상 기본 동작은 동기화입니다. 그러나 이것은 성능에 해로울 수 있기 때문에 브라우저는 가능한 한 많이 작동합니다. 그들은 구문 분석,로드 및 CSS 적용 등을 진행할 수 있습니다. 그러나 다음 스크립트 조각을 실행할 수는 없습니다. 그래서 물건이 차단됩니다. 비동기를 설정하면 브라우저에 계속 진행해도 괜찮다는 것을 알리고 직접 작동하는지 확인할 수 있습니다.
Stijn de Witt

8

로드가 완료된 모든 스크립트가 index2.html에서 동일한 라이브러리를 사용하는 index2.html로 페이지를 리디렉션 할 때 스크립트를 비동기 적으로로드했습니다 (html 5에는 해당 기능이 있음). 페이지가 index2.html로 리디렉션되면 브라우저에 캐시가 있기 때문에 index2.html은 페이지를로드하는 데 필요한 모든 것이 있으므로 1 초 이내에로드됩니다. 내 index.html 페이지에서 브라우저가 해당 이미지를 캐시에 배치 할 수 있도록 사용하려는 이미지도로드합니다. 그래서 내 index.html은 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Project Management</title>

    <!-- the purpose of this page is to load all the scripts on the browsers cache so that pages can load fast from now on -->

    <script type="text/javascript">

        function stylesheet(url) {
            var s = document.createElement('link');
            s.type = 'text/css';
            s.async = true;
            s.src = url;
            var x = document.getElementsByTagName('head')[0];
            x.appendChild(s);
        }

        function script(url) {
            var s = document.createElement('script');
            s.type = 'text/javascript';
            s.async = true;
            s.src = url;
            var x = document.getElementsByTagName('head')[0];
            x.appendChild(s);
        }

        //load scritps to the catche of browser
        (function () {            
                stylesheet('css/custom-theme/jquery-ui-1.8.16.custom.css');
                stylesheet('css/main.css');
                stylesheet('css/marquee.css');
                stylesheet('css/mainTable.css');

                script('js/jquery-ui-1.8.16.custom.min.js');
                script('js/jquery-1.6.2.min.js');
                script('js/myFunctions.js');
                script('js/farinspace/jquery.imgpreload.min.js');
                script('js/marquee.js');            
        })();

    </script>

    <script type="text/javascript">
       // once the page is loaded go to index2.html
        window.onload = function () {
            document.location = "index2.html";
        }
    </script>

</head>
<body>

<div id="cover" style="position:fixed; left:0px; top:0px; width:100%; height:100%; background-color:Black; z-index:100;">Loading</div>

<img src="images/home/background.png" />
<img src="images/home/3.png"/>
<img src="images/home/6.jpg"/>
<img src="images/home/4.png"/>
<img src="images/home/5.png"/>
<img src="images/home/8.jpg"/>
<img src="images/home/9.jpg"/>
<img src="images/logo.png"/>
<img src="images/logo.png"/>
<img src="images/theme/contentBorder.png"/>

</body>
</html>

이것에 대한 또 다른 좋은 점은 페이지에 로더를 배치 할 수 있고 페이지로드가 완료되면 로더가 사라지고 밀리 초 내에 새 페이지가 실행된다는 것입니다.


1
@MohammedShareefC 아이러니입니다. 물건을 미리로드하는 특별한 페이지는 SEO 현명한 좋은 생각처럼 들리지 않습니다. 사전로드는 훌륭하지만이를 달성하기 위해 리디렉션 할 필요는 없습니다. 숨겨진 div에 링크를 붙이면 브라우저가 자동으로 처리합니다. 그런 다음 리디렉션하지 말고 실제 페이지를 렌더링하십시오. COPY-PASTERS READ THIS :이 HTML을 사용하기 전에 ISO-88591 인코딩을 UTF-8로 변경하여 나머지 사람들이 곧 인코딩 지옥에서 벗어날 수 있도록하십시오. 감사!
Stijn de Witt


8

Google의 예

<script type="text/javascript">
  (function() {
    var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
    po.src = 'https://apis.google.com/js/plusone.js?onload=onLoadCallback';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
  })();
</script>

8

몇 가지 참고 사항 :

  • s.async = trueHTML5 doctype에는 그다지 정확하지 않습니다. s.async = 'async'(실제로 true 바로 아래 주석 에서 지적한 amn 덕분에 is correct 사용 )
  • 시간 제한을 사용하여 주문을 제어하는 ​​것은 그리 좋지 않고 안전하지 않으며 모든 시간 제한의 합계와 동일하게로드 시간을 훨씬 더 크게 만듭니다!

최근에 파일을 비동기식으로로드하는 이유가 있지만 순서대로 예제보다 기능 중심적인 방법을 권장합니다 ( console.log프로덕션 사용을 위해 제거 :)).

(function() {
    var prot = ("https:"===document.location.protocol?"https://":"http://");

    var scripts = [
        "path/to/first.js",
        "path/to/second.js",
        "path/to/third.js"
    ];

    function completed() { console.log('completed'); }  // FIXME: remove logs

    function checkStateAndCall(path, callback) {
        var _success = false;
        return function() {
            if (!_success && (!this.readyState || (this.readyState == 'complete'))) {
                _success = true;
                console.log(path, 'is ready'); // FIXME: remove logs
                callback();
            }
        };
    }

    function asyncLoadScripts(files) {
        function loadNext() { // chain element
            if (!files.length) completed();
            var path = files.shift();
            var scriptElm = document.createElement('script');
            scriptElm.type = 'text/javascript';
            scriptElm.async = true;
            scriptElm.src = prot+path;
            scriptElm.onload = scriptElm.onreadystatechange = \
                checkStateAndCall(path, loadNext); // load next file in chain when
                                                   // this one will be ready 
            var headElm = document.head || document.getElementsByTagName('head')[0];
            headElm.appendChild(scriptElm);
        }
        loadNext(); // start a chain
    }

    asyncLoadScripts(scripts);
})();

4
s.async = true이다 정확한 . 이 속성 asyncw3.org/TR/html5/scripting-1.html#attr-script-async에 있는 W3C의 HTML 5 권장 사항에서 부울로 명시 적으로 지정됩니다 . 당신은 혼란스러워합니다async DOM 인터페이스를 async구현하는 객체에 의해 노출 된 속성속성HTMLScriptElement 있습니다. 실제로를 통해 요소의 해당 속성을 조작 할 때 모든 HTML 속성이 첫 번째 텍스트 Element.setAttribute이므로 사용해야 element.setAttribute("async", "async")합니다.
AMN

"최근 비동기식으로 파일을로드해야하는 이유가 있기 때문에 순서대로 귀하의 예제에 대해 좀 더 기능 중심적인 방법을 권장합니다 [...]". 비동기가 일반적으로 "더 좋음"이라는 것을 알고 있지만 어떤 "최근"이유를 언급하고 있습니까?
BluE

나는 'if (! files.length) completed ();'를 변경했습니다. 'return'추가 : 'if (! files.length) {completed (); 반환;} '

4

HTML5 덕분에 이제 태그에 "async"를 추가하여 비동기 적으로로드 할 스크립트를 선언 할 수 있습니다.

<script async>...</script>

참고 : async 속성은 외부 스크립트 전용이며 src 속성이있는 경우에만 사용해야합니다.

참고 : 외부 스크립트를 실행할 수있는 방법에는 여러 가지가 있습니다.

  • 비동기가있는 경우 : 스크립트가 페이지의 나머지 부분과 비동기 적으로 실행됩니다 (페이지가 구문 분석을 계속하는 동안 스크립트가 실행 됨).
  • async가없고 defer가있는 경우 : 페이지가 구문 분석을 완료하면 스크립트가 실행됩니다.
  • 비동기 또는 지연이없는 경우 : 브라우저가 페이지를 계속 구문 분석하기 전에 스크립트를 가져 와서 즉시 실행합니다.

참조 : http://www.w3schools.com/tags/att_script_async.asp


2

콜백이 있는지 확인하고 인수 전달을 허용하여 zzzzBov의 답변을 완료합니다.

    function loadScript(src, callback, args) {
      var s, r, t;
      r = false;
      s = document.createElement('script');
      s.type = 'text/javascript';
      s.src = src;
      if (typeof(callback) === 'function') {
        s.onload = s.onreadystatechange = function() {
          if (!r && (!this.readyState || this.readyState === 'complete')) {
            r = true;
            callback.apply(args);
          }
        };
      };
      t = document.getElementsByTagName('script')[0];
      t.parent.insertBefore(s, t);
    }

2

그것은 단지와 JS 스크립트 처리하지만 여기에 비동기 스크립트로드에 큰 현대적인 솔루션입니다 비동기 거짓을 .

작성된 훌륭한 기사가 www.html5rocks.com - 딥 다이빙 스크립트로드의 어두운 바다에가 .

가능한 많은 솔루션을 고려한 후 저자는 본문 요소 끝에 js 스크립트를 추가하는 것이 js 스크립트에 의한 페이지 렌더링 차단을 방지하는 가장 좋은 방법이라고 결론지었습니다.

그 동안 저자는 스크립트를 비동기 적으로로드하고 실행하기를 간절히 원하는 사람들을 위해 또 다른 좋은 대체 솔루션을 추가했습니다.

네 개의 스크립트 이름 script1.js, script2.js, script3.js, script4.js이 있다고 생각 하면 async = false적용하여 할 수 있습니다 .

[
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.head.appendChild(script);
});

이제 Spec은 다음과 같이 말합니다 . 함께 다운로드하고 모두 다운로드하자마자 순서대로 실행합니다.

Firefox <3.6, Opera의 말 : 이 "비동기"가 뭔지 모르겠지만 JS를 통해 추가 된 스크립트를 추가 된 순서대로 실행합니다.

Safari 5.0 내용 : "비동기"는 이해하지만 JS로 "거짓"으로 설정하는 것은 이해하지 못합니다. 순서에 관계없이 스크립트가 도착하자마자 스크립트를 실행하겠습니다.

IE <10 내용 : "비동기"에 대해 잘 모르지만 "onreadystatechange"를 사용하는 해결 방법이 있습니다.

다른 모든 내용은 다음과 같습니다. 나는 당신의 친구입니다. 우리는 책으로 이것을 할 것입니다.

이제 IE <10 해결 방법을 사용하는 전체 코드 :

var scripts = [
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];

// Watch scripts load in IE
function stateChange() {
  // Execute as many scripts in order as we can
  var pendingScript;
  while (pendingScripts[0] && ( pendingScripts[0].readyState == 'loaded' || pendingScripts[0].readyState == 'complete' ) ) {
    pendingScript = pendingScripts.shift();
    // avoid future loading events from this script (eg, if src changes)
    pendingScript.onreadystatechange = null;
    // can't just appendChild, old IE bug if element isn't closed
    firstScript.parentNode.insertBefore(pendingScript, firstScript);
  }
}

// loop through our script urls
while (src = scripts.shift()) {
  if ('async' in firstScript) { // modern browsers
    script = document.createElement('script');
    script.async = false;
    script.src = src;
    document.head.appendChild(script);
  }
  else if (firstScript.readyState) { // IE<10
    // create a script and add it to our todo pile
    script = document.createElement('script');
    pendingScripts.push(script);
    // listen for state changes
    script.onreadystatechange = stateChange;
    // must set src AFTER adding onreadystatechange listener
    // else we’ll miss the loaded event for cached scripts
    script.src = src;
  }
  else { // fall back to defer
    document.write('<script src="' + src + '" defer></'+'script>');
  }
}

1

스크립트가 너무 느리게로드되는 한 가지 이유는 다음과 같이 페이지를로드하는 동안 모든 스크립트를 실행했기 때문입니다.

callMyFunctions();

대신에:

$(window).load(function() {
      callMyFunctions();
});

이 두 번째 스크립트는 브라우저가 스크립트 실행을 시작하기 전에 모든 Javascript 코드를 완전히로드 할 때까지 대기하여 사용자에게 페이지가 더 빨리로드 된 것처럼 보이게합니다.

로딩 시간을 줄여서 사용자 경험을 향상시키려는 경우 "로딩 화면"옵션을 선택하지 않을 것입니다. 제 생각에는 페이지가 더 느리게로드되는 것보다 훨씬 더 성 가실 것입니다.


1

나는 당신이 Modernizr를 살펴볼 것을 제안합니다 . 파일이로드되었는지 확인하고 지정한 다른 스크립트를 실행할 수있는 기능을 사용하여 자바 스크립트를 비동기식으로로드 할 수있는 작은 경량 라이브러리입니다.

다음은 jquery를로드하는 예입니다.

Modernizr.load([
  {
    load: '//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js',
    complete: function () {
      if ( !window.jQuery ) {
            Modernizr.load('js/libs/jquery-1.6.1.min.js');
      }
    }
  },
  {
    // This will wait for the fallback to load and
    // execute if it needs to.
    load: 'needs-jQuery.js'
  }
]);

1

나는 이것을 돕기 위해 작은 게시물을 썼습니다. https://timber.io/snippets/asynchronously-load-a-script-in-the-browser-with-javascript/ 여기에서 더 많은 것을 읽을 수 있지만 첨부했습니다 아래 도우미 클래스. 스크립트가로드 될 때까지 자동으로 기다렸다가 지정된 창 속성을 반환합니다.

export default class ScriptLoader {
  constructor (options) {
    const { src, global, protocol = document.location.protocol } = options
    this.src = src
    this.global = global
    this.protocol = protocol
    this.isLoaded = false
  }

  loadScript () {
    return new Promise((resolve, reject) => {
      // Create script element and set attributes
      const script = document.createElement('script')
      script.type = 'text/javascript'
      script.async = true
      script.src = `${this.protocol}//${this.src}`

      // Append the script to the DOM
      const el = document.getElementsByTagName('script')[0]
      el.parentNode.insertBefore(script, el)

      // Resolve the promise once the script is loaded
      script.addEventListener('load', () => {
        this.isLoaded = true
        resolve(script)
      })

      // Catch any errors while loading the script
      script.addEventListener('error', () => {
        reject(new Error(`${this.src} failed to load.`))
      })
    })
  }

  load () {
    return new Promise(async (resolve, reject) => {
      if (!this.isLoaded) {
        try {
          await this.loadScript()
          resolve(window[this.global])
        } catch (e) {
          reject(e)
        }
      } else {
        resolve(window[this.global])
      }
    })
  }
}

사용법은 다음과 같습니다.

const loader = new Loader({
    src: 'cdn.segment.com/analytics.js',
    global: 'Segment',
})

// scriptToLoad will now be a reference to `window.Segment`
const scriptToLoad = await loader.load()


0

글쎄, x.parentNodeHEAD 요소를 반환하므로 head 태그 바로 앞에 스크립트를 삽입합니다. 그게 문제 일 수도 있습니다.

x.parentNode.appendChild()대신 시도하십시오 .



0

LABJS 또는 RequreJS를 사용할 수 있습니다.

스크립트 로더 좋아 LABJS, RequireJS코드의 속도와 품질이 향상됩니다.


0

Fetch Injection 사용을 고려해 보셨습니까? 이러한 경우를 처리하기 위해 fetch-inject 라는 오픈 소스 라이브러리를 롤링했습니다 . 다음은 lib를 사용하는 로더의 모습입니다.

fetcInject([
  'js/jquery-1.6.2.min.js',
  'js/marquee.js',
  'css/marquee.css',
  'css/custom-theme/jquery-ui-1.8.16.custom.css',
  'css/main.css'
]).then(() => {
  'js/jquery-ui-1.8.16.custom.min.js',
  'js/farinspace/jquery.imgpreload.min.js'
})

이전 버전과의 호환성을 위해 기능 감지를 활용하고 XHR 인젝션 또는 스크립트 DOM 요소로 대체하거나를 사용하여 페이지에 태그를 인라인하기 만하면됩니다 document.write.


0

다음은 렌더링 차단 JavaScript를 제거하는 사용자 지정 솔루션입니다.

// put all your JS files here, in correct order
const libs = {
  "jquery": "https://code.jquery.com/jquery-2.1.4.min.js",
  "bxSlider": "https://cdnjs.cloudflare.com/ajax/libs/bxslider/4.2.5/jquery.bxslider.min.js",
  "angular": "https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.2/angular.min.js",
  "ngAnimate": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.2/angular-animate.min.js"
}
const loadedLibs = {}
let counter = 0

const loadAsync = function(lib) {
  var http = new XMLHttpRequest()
  http.open("GET", libs[lib], true)
  http.onload = () => {
    loadedLibs[lib] = http.responseText
    if (++counter == Object.keys(libs).length) startScripts()
  }
  http.send()
}

const startScripts = function() {
  for (var lib in libs) eval(loadedLibs[lib])
  console.log("allLoaded")
}

for (var lib in libs) loadAsync(lib)

즉, 모든 스크립트를 비동기 적으로로드 한 다음 결과적으로 실행합니다.

Github 저장소 : https://github.com/mudroljub/js-async-loader


1
작동하지 않습니다No 'Access-Control-Allow-Origin' header is present on the requested resource
Abram

1
이것이 CORS 문제입니다. stackoverflow.com/questions/20035101/…
Damjan Pavlica

0

누군가가 예를 들어 React에서 사용하고 싶다면 여기에 약간의 ES6 함수가 있습니다.

import {uniqueId} from 'lodash' // optional
/**
 * @param {String} file The path of the file you want to load.
 * @param {Function} callback (optional) The function to call when the script loads.
 * @param {String} id (optional) The unique id of the file you want to load.
 */
export const loadAsyncScript = (file, callback, id) => {
  const d = document
  if (!id) { id = uniqueId('async_script') } // optional
  if (!d.getElementById(id)) {
    const tag = 'script'
    let newScript = d.createElement(tag)
    let firstScript = d.getElementsByTagName(tag)[0]
    newScript.id = id
    newScript.async = true
    newScript.src = file
    if (callback) {
      // IE support
      newScript.onreadystatechange = () => {
        if (newScript.readyState === 'loaded' || newScript.readyState === 'complete') {
          newScript.onreadystatechange = null
          callback(file)
        }
      }
      // Other (non-IE) browsers support
      newScript.onload = () => {
        callback(file)
      }
    }
    firstScript.parentNode.insertBefore(newScript, firstScript)
  } else {
    console.error(`The script with id ${id} is already loaded`)
  }
}


-3

먼저 파일 축소를 살펴보고 속도가 크게 향상되는지 확인하는 것이 좋습니다. 호스트가 느리면 정적 콘텐츠를 CDN에 넣을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.