jQuery $ .getScript () 메소드를 사용하여 여러 JS 파일을 포함하는 방법


127

js 파일에 자바 스크립트 파일을 동적으로 포함하려고합니다. 나는 그것에 대해 약간의 연구를했고 jQuery $ .getScript () 메소드가 원하는 방법이라는 것을 알았습니다.

// jQuery
$.getScript('/path/to/imported/script.js', function()
{
    // script is now loaded and executed.
    // put your dependent JS here.
    // what if the JS code is dependent on multiple JS files? 
});

그러나이 방법이 한 번에 여러 스크립트를로드 할 수 있는지 궁금합니다. 내가 묻는 이유는 때때로 내 자바 스크립트 파일이 둘 이상의 js 파일에 의존하기 때문입니다.

미리 감사드립니다.

답변:


315

정답은

getScript()다음과 같은 약속을 사용 하고 모든 스크립트가로드 될 때까지 기다릴 수 있습니다 .

$.when(
    $.getScript( "/mypath/myscript1.js" ),
    $.getScript( "/mypath/myscript2.js" ),
    $.getScript( "/mypath/myscript3.js" ),
    $.Deferred(function( deferred ){
        $( deferred.resolve );
    })
).done(function(){
    
    //place your code here, the scripts are all loaded
    
});

깡깡이

ANOTHER 뿐인

위의 코드에서 Deferred를 추가하고 내부에서 해결하는 것은 $()jQuery 호출 내에 다른 함수를 배치 $(func)하는 것과 같습니다.

$(function() { func(); });

즉, DOM이 준비 될 때까지 대기하므로 위의 예 $.when에서는 모든 스크립트가로드 되고$.Deferred DOM 준비 콜백에서 해결 되는 호출로 인해 DOM이 준비 될 때까지 대기 합니다.


보다 일반적인 사용을 위해 편리한 기능

모든 스크립트 배열을 허용하는 유틸리티 함수는 다음과 같이 만들 수 있습니다.

$.getMultiScripts = function(arr, path) {
    var _arr = $.map(arr, function(scr) {
        return $.getScript( (path||"") + scr );
    });
        
    _arr.push($.Deferred(function( deferred ){
        $( deferred.resolve );
    }));
        
    return $.when.apply($, _arr);
}

이것처럼 사용할 수 있습니다

var script_arr = [
    'myscript1.js', 
    'myscript2.js', 
    'myscript3.js'
];

$.getMultiScripts(script_arr, '/mypath/').done(function() {
    // all scripts loaded
});

여기서 경로는 모든 스크립트 앞에 추가되며 선택 사항이기도합니다. 즉, 배열에 전체 URL이 포함 된 경우이 작업을 수행 할 수 있으며 경로를 모두 생략 할 수 있습니다.

$.getMultiScripts(script_arr).done(function() { ...

인수, 오류 등

또한 done콜백에는 전달 된 스크립트와 일치하는 여러 인수가 포함되며 각 인수는 응답을 포함하는 배열을 나타냅니다.

$.getMultiScripts(script_arr).done(function(response1, response2, response3) { ...

각 배열은 다음과 같은 것을 포함합니다. [content_of_file_loaded, status, xhr_object] . 우리는 일반적으로 스크립트가 자동으로로드되기 때문에 일반적으로 이러한 인수에 액세스 할 필요가 없으며 대부분의 경우 done콜백은 모든 스크립트가로드되었다는 것을 실제로 알게 된 것입니다. 완전성을 위해 추가하고 있습니다. 드문 경우지만로드 된 파일의 실제 텍스트에 액세스해야하거나 각 XHR 개체 또는 이와 유사한 항목에 액세스해야하는 경우가 있습니다.

또한 스크립트가로드되지 않으면 실패 핸들러가 호출되고 후속 스크립트가로드되지 않습니다.

$.getMultiScripts(script_arr).done(function() {
     // all done
}).fail(function(error) {
     // one or more scripts failed to load
}).always(function() {
     // always called, both on success and error
});

11
좋은 답변 주셔서 감사합니다. $.Deferred(function( deferred ){$( deferred.resolve );})여기에 왜 추가하는지 설명해 주시겠습니까 ?
sozhen

11
지연된 개체는 실제로 여러 스크립트를로드하고 모든 작업이 완료되면 기능을 수행 할 수 있도록하는 약속과 관련이 없습니다. $ ()가 준비되어 있는지 확인하고, 즉, document.ready와 같이 코드를 실행하기 전에 DOM이 준비되어 있는지 확인하여 첨부하는 좋은 예를 찾았습니다. 코드에 지연된 DOM 준비 기능이있는 getScript 온라인을 약속하고 좋은 생각처럼 유지하기로 결정했습니다.
adeneo

4
아약스에서 캐싱 jQuery를에 기본적으로 해제되어 있기 때문에 이제, 컴퓨터를 켭 쿼리 문자열을 제거 할 것을 : $.ajaxSetup({ cache: true });그러나 그것은 또한 당신이 캐시에 원하지 않는 다른 아약스 호출에 영향을 미칠 수있는, 많은이 더 많은이에 거기 에 대한 문서 getScript 및 cachedScript라는 캐시 된 getScript 함수를 작성하는 방법도 약간 있습니다.
adeneo

3
늦게 받아 들여서 죄송합니다. 때때로 당신의 방법은 여전히 ​​작동하지 않습니다. 이유가 무엇인지 잘 모르겠습니다. 한 번에 네 개의 스크립트 파일을 통합하려고합니다. $.when($.getScript(scriptSrc_1), $.getScript(scriptSrc_2), $.getScript(scriptSrc_3), $.getScript(scriptSrc_4), $.Deferred(function(deferred) { $(deferred.resolve); })).done(function() { ... })
sozhen

1
이 작업을 수행 할 수없는 사람은 JS 파일에 구문 분석 오류가 없는지 확인하십시오 (예 : 먼저 <script> 태그에 올바르게로드되는지 테스트하십시오). jQuery.getScript ()는 이러한 오류를로드 실패로 간주하고 .done () 대신 .fail ()이 호출됩니다. @SongtaoZ.
문 프리즘 파워

29

여러 스크립트를 병렬로로드하는 간단한 기능을 구현했습니다.

함수

function getScripts(scripts, callback) {
    var progress = 0;
    scripts.forEach(function(script) { 
        $.getScript(script, function () {
            if (++progress == scripts.length) callback();
        }); 
    });
}

용법

getScripts(["script1.js", "script2.js"], function () {
    // do something...
});

1
어떤 이유로, 이것은 Emanuel보다 더 잘 작동했습니다. 매우 투명한 구현이기도합니다.
Todd

@ satat 감사합니다 :)! 상위 답변이 일부 사용자 (나 포함)에게는 작동하지 않으므로이 솔루션을 게시했습니다. 그리고 훨씬 단순 해 보입니다.
Andrei

10

이전 스크립트의 콜백에 다음 필수 스크립트를로드하십시오.

$.getScript('scripta.js', function()
{
   $.getScript('scriptb.js', function()
   {
       // run script that depends on scripta.js and scriptb.js
   });
});

1
확실히이 방법은 스크립트를 순차적으로 다운로드하여 최종 실행 시간을 늦출 것입니까?
Jimbo

1
맞다, @Jimbo-공정하다. 조기 실행하는 것이 좋습니다. :)
Alastair

폭포는 거의 항상 피해야합니다. getScript에는 약속이 포함되어 있습니다. $ .when을 사용하여 약속이 해결 될 때들을 수 있습니다.
Roi

@Roi 및 다른 사람 : 특정 주문에 스크립트를로드해야하는 경우 기본적으로이 접근 방식에 어떤 문제가 있습니까? 그러므로 약속의 대안은 어떤 이점을 가져 옵니까?
Ifedi Okonkwo 2016

@IfediOkonkwo는 직렬로 연결해야 할 때 작동하지만 orig op는 한 번에 여러 개를 원한다고 언급했습니다 (이는 안티 패턴이 될 것입니다). 그럼에도 불구하고 직렬로 원한다면 배열을 전달할 수있는 루핑 함수를 작성합니다. 딥 네 스팅은 더러워집니다.
Roi

9

때로는 특정 순서로 스크립트를로드해야합니다. 예를 들어 jQuery UI보다 먼저 jQuery를로드해야합니다. 이 페이지의 대부분의 예제는 스크립트를 병렬로 (비동기 적으로)로드하므로 실행 순서가 보장되지 않습니다. 순서가 없으면 둘 다 성공적으로로드되었지만 순서가 잘못된 경우 y에 의존하는 스크립트 x가 중단 될 수 있습니다.

종속 스크립트의 순차적 로딩 + 선택적 병렬 로딩 + 지연된 객체 를 허용하는 하이브리드 접근법을 제안 합니다 .

/*
 * loads scripts one-by-one using recursion
 * returns jQuery.Deferred
 */
function loadScripts(scripts) {
  var deferred = jQuery.Deferred();

  function loadScript(i) {
    if (i < scripts.length) {
      jQuery.ajax({
        url: scripts[i],
        dataType: "script",
        cache: true,
        success: function() {
          loadScript(i + 1);
        }
      });
    } else {
      deferred.resolve();
    }
  }
  loadScript(0);

  return deferred;
}

/*
 * example using serial and parallel download together
 */

// queue #1 - jquery ui and jquery ui i18n files
var d1 = loadScripts([
  "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js",
  "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/i18n/jquery-ui-i18n.min.js"
]).done(function() {
  jQuery("#datepicker1").datepicker(jQuery.datepicker.regional.fr);
});

// queue #2 - jquery cycle2 plugin and tile effect plugin
var d2 = loadScripts([
  "https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/jquery.cycle2.min.js",
  "https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/plugin/jquery.cycle2.tile.min.js"

]).done(function() {
  jQuery("#slideshow1").cycle({
    fx: "tileBlind",
    log: false
  });
});

// trigger a callback when all queues are complete
jQuery.when(d1, d2).done(function() {
  console.log("All scripts loaded");
});
@import url("https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/blitzer/jquery-ui.min.css");

#slideshow1 {
  position: relative;
  z-index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<p><input id="datepicker1"></p>

<div id="slideshow1">
  <img src="https://dummyimage.com/300x100/FC0/000">
  <img src="https://dummyimage.com/300x100/0CF/000">
  <img src="https://dummyimage.com/300x100/CF0/000">
</div>

두 대기열의 스크립트는 동시에 다운로드되지만 각 대기열의 스크립트는 순서대로 다운로드되어 순서대로 실행됩니다. 폭포 형 차트 :

스크립트의 폭포 형 차트


스크립트가 메모리에로드되면 HTML에 스크립트 태그를 추가 할 필요가 없습니까?
Ankush Jain

4

사용 yepnope.js 또는 모더 나이저 등의 yepnope.js을 포함 (Modernizr.load ).

최신 정보

후속 조치를 위해 현재 yepnope를 사용하고있는 것과 동등하게 여러 스크립트에 대한 종속성을 보여줍니다.

yepnope({
  load: ['script1.js', 'script2.js', 'script3.js'],
  complete: function () {
      // all the scripts have loaded, do whatever you want here
  }
});

감사. html 파일에 태그를 yepnope.injectJs( scriptSource )포함하는 것처럼 Javascript 파일의 시작 부분에 여러 개 를 사용할 수 있습니까 <script>?
sozhen

그것은 새롭고 솔직히 왜 그것이 필요한지 이해하지 못합니다. 최근 변경 사항 목록을 약간 벗어난 문서를 따라 가면보다 일반적인 사용법을 볼 수 있습니다.
Chris Pratt

+1; 이것은 의존성을 올바르게 관리합니다 (즉, 동일한 스크립트를 두 번로드하지 않음) $.getScript. 이것은 큰 문제입니다.
ov

yepnope.js는 더 이상 사용되지 않습니다 .
Stephan

4

크로스 도메인이 완벽하게 작동하는 Ajax에 의해 성공적으로로드 된 후 실제로 실행되지 않는 스크립트의 동일한 도메인 핫로드로 하나 이상의 문제를 발생시키는 다중 스크립트로드와 관련된 여러 문제가 발생했습니다! :(

원래 질문에 선택된 답변이 안정적으로 작동하지 않습니다.

여러 번 반복 한 후에는 getScript에 대한 최종 답변이며 스크립트 당로드 된 콜백 옵션 및 완료시 전체 콜백과 함께 특정 엄격한 순서로 여러 스크립트를 비동기 적으로로드합니다 .jQuery 2.1 이상 및 최신 버전의 Chrome에서 테스트되었습니다. 버려진 Internet Explorer.

내 테스트 사례는 THREE.JS webGL 렌더 파일을로드 한 다음 onComplete에 대한 익명 함수 호출에 전달 된 간격 검사를 사용하여 THREE 전역을 사용할 수있을 때 렌더 스크립트를 시작했습니다.

프로토 타입 함수 (getScripts)

function getScripts( scripts, onScript, onComplete )
{
    this.async = true;
    this.cache = false;
    this.data = null;
    this.complete = function () { $.scriptHandler.loaded(); };
    this.scripts = scripts;
    this.onScript = onScript;
    this.onComplete = onComplete;
    this.total = scripts.length;
    this.progress = 0;
};

getScripts.prototype.fetch = function() {
    $.scriptHandler = this;
    var src = this.scripts[ this.progress ];
    console.log('%cFetching %s','color:#ffbc2e;', src);

    $.ajax({
        crossDomain:true,
        async:this.async,
        cache:this.cache,
        type:'GET',
        url: src,
        data:this.data,
        statusCode: {
            200: this.complete
        },
        dataType:'script'
    });
};

getScripts.prototype.loaded = function () {
    this.progress++;
    if( this.progress >= this.total ) {
        if(this.onComplete) this.onComplete();
    } else {
        this.fetch();
    };
    if(this.onScript) this.onScript();
};

사용하는 방법

var scripts = new getScripts(
    ['script1.js','script2.js','script.js'],
    function() {
        /* Optional - Executed each time a script has loaded (Use for Progress updates?) */
    },
    function () {
        /* Optional - Executed when the entire list of scripts has been loaded */
    }
);
scripts.fetch();

이 기능은 Deferred (Deprecated now?), When, Success & Complete in Trials를 100 % 신뢰할 수 없습니다!?를 사용하여 찾은 것과 동일합니다.

원하는 경우 오류 / 실패 처리 동작을 추가 할 수 있습니다.


+1 올바른 순서로로드하기 위해 +1, 종종 필수이며, 내가 빠진 것이 아닌 한 허용되는 답변으로 보장되지 않습니까? 아래에 비슷한 짧은 답변을 게시했지만 더 일반적인 경우입니다.
Whelkaholism

2

$.when다음 함수를 시도하여 -method를 사용할 수 있습니다.

function loadScripts(scripts) {
  scripts.forEach(function (item, i) {
    item = $.getScript(item);
  });
  return $.when.apply($, scripts);
}

이 기능은 다음과 같이 사용됩니다 :

loadScripts(['path/to/script-a.js', 'path/to/script-b.js']).done(function (respA, respB) {
    // both scripts are loaded; do something funny
});

이것이 약속을 사용하고 최소한의 오버 헤드를 갖는 방법입니다.


이렇게하면 스크립트가 순서대로로드됩니까?
CyberMonk

2

좋은 대답입니다.

답변을보다 포괄적으로 만드는 방법을 알아내는 데 약간의 시간이 걸렸습니다 (코드 정의 스크립트 배열을로드 할 수 있도록). 모든 스크립트가로드되고 실행될 때 콜백이 호출됩니다. 내 해결책은 다음과 같습니다.

    function loadMultipleScripts(scripts, callback){
        var array = [];

        scripts.forEach(function(script){
            array.push($.getScript( script ))
        });

        array.push($.Deferred(function( deferred ){
                    $( deferred.resolve );
                }));

        $.when.apply($, array).done(function(){
                if (callback){
                    callback();
                }
            });
    }

2

async = false로 스크립트 추가

여기에 다르지만 매우 간단한 접근법이 있습니다. 여러 스크립트를로드하려면 본문에 간단히 추가하면됩니다.

  • 브라우저가 페이지로드를 최적화하는 방식이므로 비동기식으로로드합니다.
  • 브라우저가 HTML 태그를 구문 분석하는 방식이므로 스크립트를 순서대로 실행합니다.
  • 스크립트가 순서대로 실행되므로 콜백이 필요하지 않습니다. 다른 스크립트를 추가하기 만하면 다른 스크립트 후에 실행됩니다.

자세한 정보는 여기 : https://www.html5rocks.com/en/tutorials/speed/script-loading/

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

1

당신이 찾고있는 것은 AMD 호환 로더입니다 (예 : require.js).

http://requirejs.org/

http://requirejs.org/docs/whyamd.html

당신이 그것을 보면 좋은 오픈 소스 것들이 많이 있습니다. 기본적으로이를 통해 코드 모듈을 정의 할 수 있으며 다른 코드 모듈에 종속 된 경우 해당 모듈의 다운로드가 끝날 때까지 기다렸다가 실행을 계속합니다. 이 방법으로 10 개의 모듈을 비동기식으로로드 할 수 있으며 다른 모듈 중 일부를 실행하더라도 문제가 발생하지 않습니다.


1

이 기능은 종속 파일이 완전히로드 된 후 파일이로드되도록합니다. 다른 파일에 대한 종속성을 염두에두고 파일을 순서대로 제공하면됩니다.

function loadFiles(files, fn) {
    if (!files.length) {
        files = [];
    }
    var head = document.head || document.getElementsByTagName('head')[0];

    function loadFile(index) {
        if (files.length > index) {
            var fileref = document.createElement('script');
            fileref.setAttribute("type", "text/javascript");
            fileref.setAttribute("src", files[index]);
            head.appendChild(fileref);
            index = index + 1;
            // Used to call a callback function
            fileref.onload = function () {
                loadFile(index);
            }
        } else if(fn){
            fn();
        }
    }
    loadFile(0);
}

파일을 순서대로로드하기 때문에 허용 된 답변보다 낫습니다. script2에 script1을로드해야하는 경우 순서가 필수적입니다.
살만 A

1

이것은 나를 위해 작동합니다 :

function getScripts(scripts) {
    var prArr = [];
    scripts.forEach(function(script) { 
        (function(script){
            prArr .push(new Promise(function(resolve){
                $.getScript(script, function () {
                    resolve();
                });
            }));
        })(script);
    });
    return Promise.all(prArr, function(){
        return true;
    });
}

그리고 그것을 사용하십시오 :

var jsarr = ['script1.js','script2.js'];
getScripts(jsarr).then(function(){
...
});

1

다음은 Maciej Sawicki를 사용 Promise하고 콜백으로 구현 한 답변입니다 .

function loadScripts(urls, path) {
    return new Promise(function(resolve) {
        urls.forEach(function(src, i) {

            let script = document.createElement('script');        
            script.type = 'text/javascript';
            script.src = (path || "") + src;
            script.async = false;

            // If last script, bind the callback event to resolve
            if(i == urls.length-1) {                    
                // Multiple binding for browser compatibility
                script.onreadystatechange = resolve;
                script.onload = resolve;
            }

            // Fire the loading
            document.body.appendChild(script);
        });
    });
}

사용하다:

let JSDependencies = ["jquery.js",
                      "LibraryNeedingJquery.js",
                      "ParametersNeedingLibrary.js"];

loadScripts(JSDependencies,'JavaScript/').then(taskNeedingParameters);

모든 Javascript 파일은 가능한 빨리 다운로드되어 지정된 순서대로 실행됩니다. 그런 다음 taskNeedingParameters호출됩니다.


0

Andrew Marc Newton의 종합 답변의 짧은 버전. 이것은 정의되지 않은 UI 동작을 피하기 위해 수행해야하는 상태 코드의 성공 여부를 확인하지 않습니다.

이것은 jQuery를 보장 할 수 있지만 다른 포함을 보장 할 수없는 성가신 시스템을위한 것이므로 강제로 외부 스크립트에 빠지지 않을 정도로 짧은 기술을 원했습니다. (인덱스 0을 첫 번째 "재귀"호출에 전달하면 더 짧아 질 수 있지만 스타일 습관이 강 해져서 설탕을 첨가하게되었습니다.)

또한 종속성 목록을 모듈 이름에 할당하고 있으므로이 블록은 "module1"이 필요한 모든 곳에 포함될 수 있으며 스크립트 및 종속 초기화는 한 번만 포함 / 실행됩니다 ( index콜백에 로그인 하여 단일 순서를 볼 수 있음) 실행중인 AJAX 요청 세트)

if(typeof(__loaders) == 'undefined') __loaders = {};

if(typeof(__loaders.module1) == 'undefined')
{
    __loaders.module1 = false;

    var dependencies = [];

    dependencies.push('/scripts/loadmefirst.js');
    dependencies.push('/scripts/loadmenext.js');
    dependencies.push('/scripts/loadmelast.js');

    var getScriptChain  = function(chain, index)        
    {
        if(typeof(index) == 'undefined')
            index = 0;

        $.getScript(chain[index], 
            function()
            {
                if(index == chain.length - 1)
                {
                    __loaders.module1 = true;

                    /* !!!
                        Do your initialization of dependent stuff here 
                    !!! */
                }
                else 
                    getScriptChain(chain, index + 1);
            }
        );
    };

    getScriptChain(dependencies);       
}

0

jQuery의 getScript 메소드를 확장하는 플러그인이 있습니다. 비동기식 및 동기식 로딩을 허용하고 jQuery의 캐싱 메커니즘을 사용합니다. 전체 공개, 나는 이것을 썼다. 더 나은 방법을 찾으면 부담없이 참여하십시오.

https://github.com/hudsonfoo/jquery-getscripts


0

n 개의 스크립트를 하나씩 로드합니다 (예 : 두 번째 파일에 첫 번째 스크립트가 필요한 경우 유용).

(function self(a,cb,i){
    i = i || 0; 
    cb = cb || function(){};    
    if(i==a.length)return cb();
    $.getScript(a[i++],self.bind(0,a,cb,i));                    
})(['list','of','script','urls'],function(){console.log('done')});

0

위의 @adeneo의 답변을 기반으로 : CSS 및 js 파일로드를 결합

개선을위한 제안?

// Usage
//$.getMultiResources(['script-1.js','style-1.css'], 'assets/somePath/')
//  .done(function () {})
//  .fail(function (error) {})
//  .always(function () {});

(function ($) {
  $.getMultiResources = function (arr, pathOptional, cache) {
    cache = (typeof cache === 'undefined') ? true : cache;
    var _arr = $.map(arr, function (src) {
      var srcpath = (pathOptional || '') + src;
      if (/.css$/i.test(srcpath)) {
        return $.ajax({
          type: 'GET',
          url: srcpath,
          dataType: 'text',
          cache: cache,
          success: function () {
            $('<link>', {
              rel: 'stylesheet',
              type: 'text/css',
              'href': srcpath
            }).appendTo('head');
          }
        });

      } else {
        return $.ajax({
          type: 'GET',
          url: srcpath,
          dataType: 'script',
          cache: cache
        });
      }
    });
    //
    _arr.push($.Deferred(function (deferred) {
      $(deferred.resolve);
    }));
    //
    return $.when.apply($, _arr);
  };
})(jQuery);

0

재귀를 사용하여 시도해 볼 수 있습니다. 그러면 전체 목록 다운로드가 완료 될 때까지 하나씩 동기화되어 다운로드됩니다.

var queue = ['url/links/go/here'];

ProcessScripts(function() { // All done do what ever you want

}, 0);

function ProcessScripts(cb, index) {
    getScript(queue[index], function() {
        index++;
        if (index === queue.length) { // Reached the end
            cb();
        } else {
            return ProcessScripts(cb, index);
        }
    });
}

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