programing

JavaScript 파일을 동적으로 로드합니다.

powerit 2023. 8. 6. 10:29
반응형

JavaScript 파일을 동적으로 로드합니다.

자바스크립트 파일을 안정적이고 동적으로 로드하려면 어떻게 해야 합니까?이를 사용하여 모듈 또는 구성 요소를 구현할 수 있습니다. 이 구성 요소는 '초기화'될 때 필요한 모든 JavaScript 라이브러리 스크립트를 요청 시 동적으로 로드합니다.

는 모든 파일을 수동으로 해야 합니다.<script>이 구성 요소를 구현하는 태그를 웹 페이지에 추가합니다. 이 구성 요소 스크립트 파일은 '주' 구성 요소입니다.

메인스트림 JavaScript 라이브러리는 어떻게 이를 수행합니까(프로토타입, jQuery 등)?이러한 도구는 여러 JavaScript 파일을 하나의 스크립트 파일의 재배포 가능한 '빌드' 버전으로 병합합니까?또는 보조 '라이브러리' 스크립트를 동적으로 로드합니까?

이 질문에 대한 추가 사항: 동적으로 포함된 JavaScript 파일이 로드된 후 이벤트를 처리할 수 있는 방법이 있습니까?프로토타입은 다음과 같습니다.document.observe문서 전반의 이벤트에 사용됩니다.예:

document.observe("dom:loaded", function() {
  // initially hide all containers for tab content
  $$('div.tabcontent').invoke('hide');
});

스크립트 요소에 사용할 수 있는 이벤트는 무엇입니까?

Javascript에는 Import / include / require가 없지만 원하는 것을 달성하는 방법은 크게 두 가지가 있습니다.

1 - AJAX 호출과 함께 로드한 후 eval을 사용할 수 있습니다.

이것은 가장 간단한 방법이지만 자바스크립트 안전 설정 때문에 당신의 도메인으로 제한되며, eval을 사용하는 것은 버그와 해킹에 대한 문을 여는 것입니다.

2 - HTML에 스크립트 URL이 있는 스크립트 요소를 추가합니다.

확실히 최선의 방법입니다.외부 서버에서도 스크립트를 로드할 수 있으며, 브라우저 파서를 사용하여 코드를 평가하므로 깨끗합니다.다음을 입력할 수 있습니다.scripthead페이지의 웹 페이지의 맨 아래에 .body.

이 두 가지 솔루션에 대해 설명하고 설명합니다.

자, 여러분이 알아야 할 큰 문제가 있습니다.이렇게 하면 코드를 원격으로 로드할 수 있습니다.최신 웹 브라우저는 성능을 향상시키기 위해 모든 것을 비동기식으로 로드하기 때문에 파일을 로드하고 현재 스크립트를 계속 실행합니다.

즉, 이러한 트릭을 직접 사용할 경우 새로 로드된 코드가 계속 로드되고 있기 때문에 로드를 요청한 다음 줄에는 새로 로드된 코드를 사용할 수 없습니다.

E.G: my_lovely_script.js에는 MySuperObject가 포함되어 있습니다.

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

그런 다음 F5를 눌러 페이지를 다시 로드합니다.효과가 있습니다!혼란스러운...

그래서 어떻게 해야 할까요?

글쎄요, 제가 드린 링크에서 저자가 제안하는 해킹을 사용하시면 됩니다.요약하자면, 급한 사람들을 위해, 그는 스크립트가 로드될 때 콜백 기능을 실행하기 위해 이벤트를 사용합니다.그래서 당신은 원격 라이브러리를 사용하는 모든 코드를 콜백 기능에 넣을 수 있습니다.예:

function loadScript(url, callback)
{
    // adding the script element to the head as suggested before
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.type = 'text/javascript';
   script.src = url;

   // then bind the event to the callback function 
   // there are several events for cross browser compatibility
   script.onreadystatechange = callback;
   script.onload = callback;

   // fire the loading
   head.appendChild(script);
}

그런 다음 스크립트가 람다 함수에 로드된 후 사용할 코드를 작성합니다.

var myPrettyCode = function() {
    // here, do what ever you want
};

그런 다음 이 모든 것을 실행합니다.

loadScript("my_lovely_script.js", myPrettyCode);

네, 알았어요.하지만 이 모든 것을 쓰는 것은 고통입니다.

이런 경우에는 항상 환상적인 무료 jQuery 프레임워크를 사용할 수 있습니다. 이 프레임워크를 사용하면 한 줄에서 동일한 작업을 수행할 수 있습니다.

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});

프로토타입을 사용하여 스크립트 요소를 동적으로 작성할 수 있습니다.

new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});

여기서 문제는 외부 스크립트 파일이 언제 완전히 로드되는지 알 수 없다는 것입니다.

우리는 종종 종속 코드가 다음 줄에 있기를 원하며 다음과 같은 것을 작성하기를 원합니다.

if (iNeedSomeMore) {
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
    myFancyMethod(); // cool, no need for callbacks!
}

콜백 없이 스크립트 종속성을 주입하는 현명한 방법이 있습니다.동기식 AJAX 요청을 통해 스크립트를 풀링하고 글로벌 수준에서 스크립트를 평가하기만 하면 됩니다.

프로토타입을 사용하는 경우 Script.load 방법은 다음과 같습니다.

var Script = {
    _loadedScripts: [],
    include: function(script) {
        // include script only once
        if (this._loadedScripts.include(script)) {
            return false;
        }
        // request file synchronous
        var code = new Ajax.Request(script, {
            asynchronous: false,
            method: "GET",
            evalJS: false,
            evalJSON: false
        }).transport.responseText;
        // eval code on global level
        if (Prototype.Browser.IE) {
            window.execScript(code);
        } else if (Prototype.Browser.WebKit) {
            $$("head").first().insert(Object.extend(
                new Element("script", {
                    type: "text/javascript"
                }), {
                    text: code
                }
            ));
        } else {
            window.eval(code);
        }
        // remember included script
        this._loadedScripts.push(script);
    }
};

저는 최근jQuery에서 훨씬복잡한 버전을 사용했습니다.

<script src="scripts/jquery.js"></script>
<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  var $head = $("head");
  for (var i = 0; i < js.length; i++) {
    $head.append("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>

IE6/7, Firefox, Safari, Opera 등 제가 테스트한 모든 브라우저에서 잘 작동했습니다.

업데이트: jQuery-less 버전:

<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  for (var i = 0, l = js.length; i < l; i++) {
    document.getElementsByTagName("head")[0].innerHTML += ("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>

나는 기본적으로 당신이 아담을 했던 것과 같은 일을 했지만, 내가 확실히 하기 위해 약간 수정했습니다.head작업을 완료하기 위한 요소. 간히생습다니했성단을 .include스크립트와 CSS 파일을 모두 처리하는 함수(아래 코드).

이 기능은 또한 스크립트나 CSS 파일이 동적으로 로드되지 않았는지 확인합니다.수동으로 코드화된 값을 확인하지 않으며 이를 위한 더 나은 방법이 있을 수 있지만 목적에 부합합니다.

function include( url, type ){
    // First make sure it hasn't been loaded by something else.
    if( Array.contains( includedFile, url ) )
        return;
     
    // Determine the MIME type.
    var jsExpr = new RegExp( "js$", "i" );
    var cssExpr = new RegExp( "css$", "i" );
    if( type == null )
        if( jsExpr.test( url ) )
            type = 'text/javascript';
        else if( cssExpr.test( url ) )
            type = 'text/css';
            
    // Create the appropriate element.
    var element = null;
    switch( type ){
        case 'text/javascript' :
            element = document.createElement( 'script' );
            element.type = type;
            element.src = url;
            break;
        case 'text/css' :
            element = document.createElement( 'link' );
            element.rel = 'stylesheet';
            element.type = type;
            element.href = url;
            break;
    }
    
    // Insert it to the <head> and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( element );
    Array.add( includedFile, url );
}

또 다른 멋진 대답

$.getScript("my_lovely_script.js", function(){


   alert("Script loaded and executed.");
  // here you can use anything you defined in the loaded script

 });

https://stackoverflow.com/a/950146/671046

동적 모듈 가져오기가 Firefox 67+에 착륙했습니다.

(async () => {
   await import('./synth/BubbleSynth.js')
})()

오류 처리 포함:

(async () => {
    await import('./synth/BubbleSynth.js').catch((error) => console.log('Loading failed' + error))
})()

또한 모든 종류의 비모듈 라이브러리에도 사용할 수 있습니다. 이 경우 lib는 객체, 오래된 방식으로 사용할 수 있지만 요청 시에만 사용할 수 있습니다. 이것은 좋은 일입니다.

suncalc.js를 사용하는 예에서는 이러한 방식으로 작동하려면 서버에 CORS가 활성화되어 있어야 합니다!

(async () => {
 await import('https://cdnjs.cloudflare.com/ajax/libs/suncalc/1.8.0/suncalc.min.js')
 .then( () => {
   let times = SunCalc.getTimes(new Date(), 51.5,-0.1);
   console.log("Golden Hour today in London: " + times.goldenHour.getHours() + ':' + times.goldenHour.getMinutes() + ". Take your pics!")
  })
})()

https://caniuse.com/ #messages=es6-messages-dynamic-import

여기 제가 찾은 몇 가지 예제 코드가 있습니다.더 좋은 방법이 있습니까?

  function include(url)
  {
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.setAttribute("src", url);
    var nodes = document.getElementsByTagName("*");
    var node = nodes[nodes.length -1].parentNode;
    node.appendChild(s);
  }

jQuery를 이미 로드한 경우 $.getScript를 사용해야 합니다.

이것은 (의존 코드가 실행되기 전에 스크립트가 로드되도록 보장하는) 콜백 기능이 내장되어 있고 캐싱을 제어할 수 있다는 점에서 다른 답변보다 이점이 있습니다.

약속을 사용하면 다음과 같이 단순화할 수 있습니다.로더 기능:

  const loadCDN = src =>
    new Promise((resolve, reject) => {
      if (document.querySelector(`head > script[src="${src}"]`) !== null) return resolve()
      const script = document.createElement("script")
      script.src = src
      script.async = true
      document.head.appendChild(script)
      script.onload = resolve
      script.onerror = reject
    })

사용량(비동기/대기):

await loadCDN("https://.../script.js")

사용량(약속):

loadCDN("https://.../script.js").then(res => {}).catch(err => {})

참고: 비슷한 솔루션이 하나 있었지만 스크립트가 이미 로드되었는지 확인하지 않고 매번 스크립트를 로드합니다.이것은 src 속성을 확인합니다.

SYNC 스크립트를 로드하려면 HTML HEAD 요소에 스크립트 텍스트를 직접 추가해야 합니다.as를 추가하면 ASYNC 로드가 트리거됩니다.외부 파일에서 스크립트 텍스트를 동기화하여 로드하려면 XHR을 사용합니다.빠른 샘플 아래(이 게시물과 다른 게시물의 다른 답변 일부를 사용하고 있습니다):

/*sample requires an additional method for array prototype:*/

if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
    var i = this.length;
    while (i--) { if (this[i] === obj) return true; }
    return false;
};
};

/*define object that will wrap our logic*/
var ScriptLoader = {
LoadedFiles: [],

LoadFile: function (url) {
    var self = this;
    if (this.LoadedFiles.contains(url)) return;

    var xhr = new XMLHttpRequest();
    xhr.onload = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                self.LoadedFiles.push(url);
                self.AddScript(xhr.responseText);
            } else {
                if (console) console.error(xhr.statusText);
            }
        }
    };
    xhr.open("GET", url, false);/*last parameter defines if call is async or not*/
    xhr.send(null);
},

AddScript: function (code) {
    var oNew = document.createElement("script");
    oNew.type = "text/javascript";
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
}
};

/*Load script file. ScriptLoader will check if you try to load a file that has already been loaded (this check might be better, but I'm lazy).*/

ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
/*this will be executed right after upper lines. It requires jquery to execute. It requires a HTML input with id "tb1"*/
$(function () { alert($('#tb1').val()); });

더 좋은 방법이 있습니까?

본문에 스크립트를 추가하는 것이 페이지의 마지막 노드에 추가하는 것보다 쉬울 것 같습니다.이거 어때:

function include(url) {
  var s = document.createElement("script");
  s.setAttribute("type", "text/javascript");
  s.setAttribute("src", url);
  document.body.appendChild(s);
}

인터넷에서 찾은 또 다른 솔루션을 사용했습니다.이것은 크리에이티브 커먼 하에 있으며 함수를 호출하기 전에 소스가 포함되었는지 확인합니다...

파일은 여기에서 찾을 수 있습니다: include.js

/** include - including .js files from JS - bfults@gmail.com - 2005-02-09
 ** Code licensed under Creative Commons Attribution-ShareAlike License 
 ** http://creativecommons.org/licenses/by-sa/2.0/
 **/              
var hIncludes = null;
function include(sURI)
{   
  if (document.getElementsByTagName)
  {   
    if (!hIncludes)
    {
      hIncludes = {}; 
      var cScripts = document.getElementsByTagName("script");
      for (var i=0,len=cScripts.length; i < len; i++)
        if (cScripts[i].src) hIncludes[cScripts[i].src] = true;
    }
    if (!hIncludes[sURI])
    {
      var oNew = document.createElement("script");
      oNew.type = "text/javascript";
      oNew.src = sURI;
      hIncludes[sURI]=true;
      document.getElementsByTagName("head")[0].appendChild(oNew);
    }
  }   
} 

YUI 3의 훌륭한 기능에 대해 알게 되었습니다(미리 보기 릴리스에서 사용할 수 있는 쓰기 시점).YUI Loader라는 코드 없이 YUI 라이브러리와 "외부" 모듈(찾는 항목)에 종속성을 쉽게 삽입할 수 있습니다.

또한 외부 모듈이 로드되는 즉시 호출되는 기능과 관련된 두 번째 질문에 답합니다.

예:

YUI({
    modules: {
        'simple': {
            fullpath: "http://example.com/public/js/simple.js"
        },
        'complicated': {
            fullpath: "http://example.com/public/js/complicated.js"
            requires: ['simple']  // <-- dependency to 'simple' module
        }
    },
    timeout: 10000
}).use('complicated', function(Y, result) {
    // called as soon as 'complicated' is loaded
    if (!result.success) {
        // loading failed, or timeout
        handleError(result.msg);
    } else {
        // call a function that needs 'complicated'
        doSomethingComplicated(...);
    }
});

나에게 완벽하게 효과가 있었고 의존성을 관리하는 이점이 있습니다.YUI 2 캘린더의 예는 YUI 설명서를 참조하십시오.

제 대답이 이 질문에 조금 늦었다는 것은 알지만, 여기 www.html5rocks.com 의 훌륭한 기사가 있습니다 - 스크립트 로딩의 탁한속으로 깊이 들어가 보세요.

이 기사에서 브라우저 지원과 관련하여 콘텐츠 렌더링을 차단하지 않고 JavaScript 파일을 동적으로 로드하는 가장 좋은 방법은 다음과 같은 방법이라고 결론 내렸습니다.

네 개의 스크립트에 이름이 지정되어 있다는 것을 고려하면script1.js, script2.js, script3.js, script4.js그런 다음 비동기 = 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);
});

이제 사양은 다음과 같습니다.함께 다운로드하고, 모든 다운로드 즉시 순서대로 실행합니다.

Firefox < 3.6, Opera는 다음과 같이 말합니다.저는 이 "비동기화"라는 것이 무엇인지 전혀 모르지만, 우연히 JS를 통해 추가된 스크립트를 추가된 순서대로 실행합니다.

Safari 5.0의 특징:"비동기화"는 이해하지만 JS에서 "거짓"으로 설정하는 것은 이해할 수 없습니다.당신의 스크립트가 도착하는 즉시, 어떤 순서로든 실행하겠습니다.

IE < 10은 다음과 같습니다."비동기화"에 대해서는 모르지만 "준비 상태 변경"을 사용하는 해결 방법이 있습니다.

다른 모든 것은 다음과 같습니다.저는 당신의 친구입니다. 우리는 규칙대로 이 일을 할 것입니다.

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') {
    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>');
  }
}

몇 가지 속임수와 최소화 후, 362바이트입니다.

!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
  "//other-domain.com/1.js",
  "2.js"
])

최근 크롬과 사파리에 통합된 동적 가져오기라는 새로운 ECMA 표준이 제안되었습니다.

const moduleSpecifier = './dir/someModule.js';

import(moduleSpecifier)
   .then(someModule => someModule.foo()); // executes foo method in someModule

우리가 직장에서 사용하는 기술은 AJAX 요청을 사용하여 javascript 파일을 요청한 후 반품을 평가()하는 것입니다.프로토타입 라이브러리를 사용하는 경우 Ajax에서 이 기능을 지원합니다.요청 전화.

jquery는 .jquery 함수로 나를 위해 이것을 해결했습니다 - 이것을 사용하여 완전한 jquery ui 패키지를 로드했습니다.

/*
 * FILENAME : project.library.js
 * USAGE    : loads any javascript library
 */
    var dirPath = "../js/";
    var library = ["functions.js","swfobject.js","jquery.jeditable.mini.js","jquery-ui-1.8.8.custom.min.js","ui/jquery.ui.core.min.js","ui/jquery.ui.widget.min.js","ui/jquery.ui.position.min.js","ui/jquery.ui.button.min.js","ui/jquery.ui.mouse.min.js","ui/jquery.ui.dialog.min.js","ui/jquery.effects.core.min.js","ui/jquery.effects.blind.min.js","ui/jquery.effects.fade.min.js","ui/jquery.effects.slide.min.js","ui/jquery.effects.transfer.min.js"];

    for(var script in library){
        $('head').append('<script type="text/javascript" src="' + dirPath + library[script] + '"></script>');
    }

사용하려면 - jquery.js를 가져온 후 html/php/etc 머리에 이 하나의 파일을 포함하여 라이브러리 전체에 로드하고 머리에 추가할 수 있습니다.

<script type="text/javascript" src="project.library.js"></script>

멋지고, 짧고, 단순하고, 유지 가능하게 유지하세요! :]

// 3rd party plugins / script (don't forget the full path is necessary)
var FULL_PATH = '', s =
[
    FULL_PATH + 'plugins/script.js'      // Script example
    FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library 
    FULL_PATH + 'plugins/crypto-js/hmac-sha1.js',      // CryptoJS
    FULL_PATH + 'plugins/crypto-js/enc-base64-min.js'  // CryptoJS
];

function load(url)
{
    var ajax = new XMLHttpRequest();
    ajax.open('GET', url, false);
    ajax.onreadystatechange = function ()
    {
        var script = ajax.response || ajax.responseText;
        if (ajax.readyState === 4)
        {
            switch(ajax.status)
            {
                case 200:
                    eval.apply( window, [script] );
                    console.log("library loaded: ", url);
                    break;
                default:
                    console.log("ERROR: library not loaded: ", url);
            }
        }
    };
    ajax.send(null);
}

 // initialize a single load 
load('plugins/script.js');

// initialize a full load of scripts
if (s.length > 0)
{
    for (i = 0; i < s.length; i++)
    {
        load(s[i]);
    }
}

이 코드는 모든(또는 주어진) 플랫폼에서 전체 지원을 위해 추가 기능이 필요할 수 있는 간단한 기능 예제입니다.

이런 거...

<script>
     $(document).ready(function() {
          $('body').append('<script src="https://maps.googleapis.com/maps/api/js?key=KEY&libraries=places&callback=getCurrentPickupLocation" async defer><\/script>');
     });
</script>

JQuery 접근법이 얼마나 편리한지는 제가 좋아하는 만큼, JavaScript 접근법은 그렇게 복잡하지는 않지만 이미 사용하고 있는 것을 약간 수정하면 됩니다.다음은 JS를 동적으로 로드하고(필요한 경우에만) 로드될 때까지 기다렸다가 JS에 종속된 스크립트를 실행하는 방법은 다음과 같습니다.

자바스크립트 접근법

//Create a script element that will load
let dynamicScript = document.createElement('script');

//Set source to the script we need to load
dynamicScript.src = 'linkToNeededJsFile.js';

//Set onload to callback function that depends on this script or do inline as shown below
dynamicScript.onload = () => {

    //Code that depends on the loaded script should be here

};

//append the created script element to body element
document.body.append(dynamicScript);

JS를 통해 이를 달성할 수 있는 다른 방법이 있지만, 모든 개발자가 관련할 수 있는 기본적인 JS 지식이 필요하기 때문에 이를 선호합니다.

답변의 일부는 아니지만 이미 JQuery가 포함된 프로젝트에서 선호하는 JQuery 버전은 다음과 같습니다.

$.getScript('linkToNeededJsFile.js', () => {

    //Code that depends on the loaded script should be here

});

JQuery 옵션에 대한 자세한 내용은 여기를 참조하십시오.

효과:

await new Promise((resolve, reject) => {
  let js = document.createElement("script"); 
  js.src = "mylibrary.js"; 
  js.onload = resolve; 
  js.onerror = reject; 
  document.body.appendChild(js)
});

가져오기를 원하는 스크립트가 모듈인 경우 이 기능을 사용할 수 있습니다.

이 목적을 위해 특별히 설계된 스크립트가 있습니다.

옙nope.js는 Modernizr에 내장되어 있으며 lab.js는 더 최적화된 버전입니다(그러나 사용자 친화적이지는 않습니다).

스크립트 로더의 주요 이점 중 하나는 스크립트를 조기에 로드할 수 있다는 것이기 때문에 jquery나 프로토타입과 같은 큰 라이브러리를 통해 스크립트를 동적으로 로드할지 여부를 확인하기 위해 검사를 실행하기 전에 jquery와 모든 돔 요소가 로드될 때까지 기다릴 필요가 없습니다.

자바스크립트로 모듈 스크립트를 가져오거나 포함하는 작업을 자동화하는 간단한 모듈을 작성했습니다.한번 해보고 피드백을 좀 남겨주세요! :) 코드에 대한 자세한 설명은 다음 블로그 게시물을 참조하십시오. http://stamat.wordpress.com/2013/04/12/javascript-require-import-include-modules/

var _rmod = _rmod || {}; //require module namespace
_rmod.on_ready_fn_stack = [];
_rmod.libpath = '';
_rmod.imported = {};
_rmod.loading = {
    scripts: {},
    length: 0
};

_rmod.findScriptPath = function(script_name) {
    var script_elems = document.getElementsByTagName('script');
    for (var i = 0; i < script_elems.length; i++) {
        if (script_elems[i].src.endsWith(script_name)) {
            var href = window.location.href;
            href = href.substring(0, href.lastIndexOf('/'));
            var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length);
            return url.substring(href.length+1, url.length);
        }
    }
    return '';
};

_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark the root directory of your library, any library


_rmod.injectScript = function(script_name, uri, callback, prepare) {

    if(!prepare)
        prepare(script_name, uri);

    var script_elem = document.createElement('script');
    script_elem.type = 'text/javascript';
    script_elem.title = script_name;
    script_elem.src = uri;
    script_elem.async = true;
    script_elem.defer = false;

    if(!callback)
        script_elem.onload = function() {
            callback(script_name, uri);
        };

    document.getElementsByTagName('head')[0].appendChild(script_elem);
};

_rmod.requirePrepare = function(script_name, uri) {
    _rmod.loading.scripts[script_name] = uri;
    _rmod.loading.length++;
};

_rmod.requireCallback = function(script_name, uri) {
    _rmod.loading.length--;
    delete _rmod.loading.scripts[script_name];
    _rmod.imported[script_name] = uri;

    if(_rmod.loading.length == 0)
        _rmod.onReady();
};

_rmod.onReady = function() {
    if (!_rmod.LOADED) {
        for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){
            _rmod.on_ready_fn_stack[i]();
        });
        _rmod.LOADED = true;
    }
};

//you can rename based on your liking. I chose require, but it can be called include or anything else that is easy for you to remember or write, except import because it is reserved for future use.
var require = function(script_name) {
    var np = script_name.split('.');
    if (np[np.length-1] === '*') {
        np.pop();
        np.push('_all');
    }

    script_name = np.join('.');
    var uri = _rmod.libpath + np.join('/')+'.js';
    if (!_rmod.loading.scripts.hasOwnProperty(script_name) 
     && !_rmod.imported.hasOwnProperty(script_name)) {
        _rmod.injectScript(script_name, uri, 
            _rmod.requireCallback, 
                _rmod.requirePrepare);
    }
};

var ready = function(fn) {
    _rmod.on_ready_fn_stack.push(fn);
};

// ----- USAGE -----

require('ivar.util.array');
require('ivar.util.string');
require('ivar.net.*');

ready(function(){
    //do something when required scripts are loaded
});

이 모든 샘플을 잃어버렸는데 오늘은 메인 .js에서 외부 .js를 로드해야 해서 이렇게 했습니다.

document.write("<script src='https://www.google.com/recaptcha/api.js'></script>");

콜백 및 IE 지원이 포함된 간단한 것은 다음과 같습니다.

function loadScript(url, callback) {

    var script = document.createElement("script")
    script.type = "text/javascript";

    if (script.readyState) { //IE
        script.onreadystatechange = function () {
            if (script.readyState == "loaded" || script.readyState == "complete") {
                script.onreadystatechange = null;
                callback();
            }
        };
    } else { //Others
        script.onload = function () {
            callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

loadScript("https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function () {

     //jQuery loaded
     console.log('jquery loaded');

});

다음은 JS 파일을 로드하는 함수에 대한 간단한 예입니다.관련 사항:

  • jQuery가 필요하지 않으므로 처음에는 jQuery.js 파일도 로드하는 데 사용할 수 있습니다.
  • 콜백과 비동기식입니다.
  • 로드된 URL 레코드가 포함된 인클로저를 유지하므로 한 번만 로드되도록 보장하므로 네트워크 사용을 방지합니다.
  • jQuery와 반대로$.ajax또는$.getScript넌스를 사용하여 CSP로 문제를 해결할 수 있습니다.unsafe-inline그냥 부동산을 사용하세요.script.nonce
var getScriptOnce = function() {

    var scriptArray = []; //array of urls (closure)

    //function to defer loading of script
    return function (url, callback){
        //the array doesn't have such url
        if (scriptArray.indexOf(url) === -1){

            var script=document.createElement('script');
            script.src=url;
            var head=document.getElementsByTagName('head')[0],
                done=false;

            script.onload=script.onreadystatechange = function(){
                if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
                    done=true;
                    if (typeof callback === 'function') {
                        callback();
                    }
                    script.onload = script.onreadystatechange = null;
                    head.removeChild(script);

                    scriptArray.push(url);
                }
            };

            head.appendChild(script);
        }
    };
}();

이제 간단하게 사용할 수 있습니다.

getScriptOnce("url_of_your_JS_file.js");

한 줄기를 사랑하는 분들을 위해:

import('./myscript.js');

다음과 같은 오류가 발생할 수 있습니다.

오리진 'http://127.0.0.1'의 'http://myscript.js' 스크립트'에 대한 스크립트 액세스가 CORS 정책에 의해 차단되었습니다.요청한 리소스에 'Access-Control-Allow-Origin' 헤더가 없습니다.

이 경우 다음과 같은 작업을 수행할 수 있습니다.

fetch('myscript.js').then(r => r.text()).then(t => new Function(t)());

이 함수는 메모리를 사용합니다.그리고 동일한 스크립트를 두 번 로드하고 실행할 때 충돌 없이 여러 번 호출할 수 있습니다.또한 스크립트가 실제로 로드되기 전에는 해결되지 않습니다(@radulle answer).

const loadScript = function () {
    let cache = {};
    return function (src) {
        return cache[src] || (cache[src] = new Promise((resolve, reject) => {
            let s = document.createElement('script');
            s.defer = true;
            s.src = src;
            s.onload = resolve;
            s.onerror = reject;
            document.head.append(s);
        }));
    }
}();

함수 식 뒤에 괄호()가 표시됩니다.

스크립트 병렬 로드:

Promise.all([
    loadScript('/script1.js'),
    loadScript('/script2.js'),
    // ...
]).then(() => {
    // do something
})

동적 적재 스타일시트에 동일한 방법을 사용할 수 있습니다.

jscript, prototype, YUI와 같은 모든 주요 Javascript 라이브러리는 스크립트 파일 로드를 지원합니다.예를 들어 YUI에서 코어를 로드한 후 다음을 수행하여 캘린더 컨트롤을 로드할 수 있습니다.

var loader = new YAHOO.util.YUILoader({

    require: ['calendar'], // what components?

    base: '../../build/',//where do they live?

    //filter: "DEBUG",  //use debug versions (or apply some
                        //some other filter?

    //loadOptional: true, //load all optional dependencies?

    //onSuccess is the function that YUI Loader
    //should call when all components are successfully loaded.
    onSuccess: function() {
        //Once the YUI Calendar Control and dependencies are on
        //the page, we'll verify that our target container is 
        //available in the DOM and then instantiate a default
        //calendar into it:
        YAHOO.util.Event.onAvailable("calendar_container", function() {
            var myCal = new YAHOO.widget.Calendar("mycal_id", "calendar_container");
            myCal.render();
        })
     },

    // should a failure occur, the onFailure function will be executed
    onFailure: function(o) {
        alert("error: " + YAHOO.lang.dump(o));
    }

 });

// Calculate the dependency and insert the required scripts and css resources
// into the document
loader.insert();

위의 게시물 중 일부를 작업 예시와 함께 수정했습니다.여기서 우리는 같은 배열의 css와 js도 줄 수 있습니다.

$(document).ready(function(){

if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
    var i = this.length;
    while (i--) { if (this[i] === obj) return true; }
    return false;
};
};

/* define object that will wrap our logic */
var jsScriptCssLoader = {

jsExpr : new RegExp( "js$", "i" ),
cssExpr : new RegExp( "css$", "i" ),
loadedFiles: [],

loadFile: function (cssJsFileArray) {
    var self = this;
    // remove duplicates with in array
    cssJsFileArray.filter((item,index)=>cssJsFileArray.indexOf(item)==index)
    var loadedFileArray = this.loadedFiles;
    $.each(cssJsFileArray, function( index, url ) {
            // if multiple arrays are loaded the check the uniqueness
            if (loadedFileArray.contains(url)) return;
            if( self.jsExpr.test( url ) ){
                $.get(url, function(data) {
                    self.addScript(data);
                });

            }else if( self.cssExpr.test( url ) ){
                $.get(url, function(data) {
                    self.addCss(data);
                });
            }

            self.loadedFiles.push(url);
    });

    // don't load twice accross different arrays

},
addScript: function (code) {
    var oNew = document.createElement("script");
    oNew.type = "text/javascript";
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
},
addCss: function (code) {
    var oNew = document.createElement("style");
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
}

};


//jsScriptCssLoader.loadFile(["css/1.css","css/2.css","css/3.css"]);
jsScriptCssLoader.loadFile(["js/common/1.js","js/2.js","js/common/file/fileReader.js"]);
});

언급URL : https://stackoverflow.com/questions/21294/dynamically-load-a-javascript-file

반응형