โหลดไฟล์ JavaScript แบบไดนามิก


167

คุณจะโหลดไฟล์ JavaScript ได้อย่างไรและเชื่อถือได้? สิ่งนี้จะถูกนำมาใช้เพื่อนำโมดูลหรือส่วนประกอบมาใช้เมื่อ 'เริ่มต้น' คอมโพเนนต์จะโหลดสคริปต์ไลบรารี JavaScript ที่ต้องการทั้งหมดแบบไดนามิกตามความต้องการ

ไคลเอนต์ที่ใช้องค์ประกอบไม่จำเป็นต้องโหลดไฟล์สคริปต์ไลบรารีทั้งหมด (และใส่<script>แท็กลงในหน้าเว็บด้วยตนเอง) ที่ใช้ส่วนประกอบนี้ - เพียงไฟล์สคริปต์คอมโพเนนต์ 'หลัก'

ไลบรารี JavaScript หลักสำเร็จได้อย่างไร (Prototype, jQuery ฯลฯ ) เครื่องมือเหล่านี้รวมไฟล์ JavaScript หลายไฟล์ไว้ในไฟล์สคริปต์เวอร์ชัน 'build' ที่สามารถเผยแพร่ซ้ำได้หรือไม่ หรือพวกเขาจะทำการโหลดแบบไดนามิกใด ๆ ของสคริปต์ 'ห้องสมุด' เสริม?

นอกเหนือจากคำถามนี้: มีวิธีจัดการเหตุการณ์หลังจากโหลดไฟล์ JavaScript ที่รวมอยู่แบบไดนามิกหรือไม่ ต้นแบบมีdocument.observeสำหรับเหตุการณ์ทั้งเอกสาร ตัวอย่าง:

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

เหตุการณ์ที่มีอยู่สำหรับองค์ประกอบสคริปต์คืออะไร?


มีความเป็นไปได้ที่ซ้ำกันของวิธีรวมไฟล์ JavaScript ในไฟล์ JavaScript อื่น
bjb568

คำตอบ:


84

คุณสามารถเขียนแท็กสคริปต์แบบไดนามิก (โดยใช้ต้นแบบ ):

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 แบบซิงโครนัสและประเมินสคริปต์ในระดับสากล

หากคุณใช้ Prototype วิธี 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);
    }
};

ฉันจะทำอย่างไรเพื่อให้ทำงานข้ามโดเมนได้ (กำลังโหลดสคริปต์จากhttp://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
2284570


@Ciastopiekarz: ฉันไม่สามารถควบคุมweb.archive.orgได้
2284570

จากนั้นคุณต้องขูดข้อมูลที่คุณต้องการเข้าถึงโดยใช้โปรแกรมอื่นและมอบให้กับตัวคุณเอง
David Schumann

Ajax.Request คืออะไร ??
bluejayke

72

ไม่มีการนำเข้า / รวม / ต้องการในจาวาสคริปต์ แต่มีสองวิธีหลักในการบรรลุสิ่งที่คุณต้องการ:

1 - คุณสามารถโหลดด้วยการโทร AJAX จากนั้นใช้ eval

นี่เป็นวิธีที่ตรงไปตรงมาที่สุด แต่ถูก จำกัด ไว้ที่โดเมนของคุณเนื่องจากการตั้งค่าความปลอดภัยของ Javascript และการใช้ eval กำลังเปิดประตูสู่ข้อบกพร่องและแฮ็ก

2 - เพิ่มแท็กสคริปต์ด้วย URL สคริปต์ใน HTML

วิธีที่ดีที่สุดแน่นอน คุณสามารถโหลดสคริปต์ได้จากเซิร์ฟเวอร์ต่างประเทศและมันก็สะอาดเมื่อคุณใช้ตัวแยกวิเคราะห์เบราว์เซอร์เพื่อประเมินรหัส คุณสามารถใส่แท็กในส่วนหัวของหน้าเว็บหรือที่ด้านล่างของร่างกาย

โซลูชันทั้งสองนี้ถูกกล่าวถึงและแสดงไว้ที่นี่

ขณะนี้มีปัญหาใหญ่ที่คุณต้องรู้ การทำเช่นนี้หมายความว่าคุณโหลดโค้ดจากระยะไกล เว็บเบราว์เซอร์สมัยใหม่จะโหลดไฟล์และดำเนินการกับสคริปต์ปัจจุบันของคุณเพราะจะโหลดทุกอย่างแบบอะซิงโครนัสเพื่อปรับปรุงประสิทธิภาพ

หมายความว่าหากคุณใช้เทคนิคเหล่านี้โดยตรงคุณจะไม่สามารถใช้รหัสที่เพิ่งโหลดใหม่ในบรรทัดถัดไปหลังจากที่คุณขอให้โหลดเพราะมันจะยังคงโหลดอยู่

EG: 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 อีกครั้ง และมันใช้งานได้! ทำให้เกิดความสับสน ...

ดังนั้นจะทำอย่างไรกับมัน?

คุณสามารถใช้แฮ็คที่ผู้เขียนแนะนำในลิงก์ที่ฉันให้ไว้ โดยสรุปสำหรับคนที่รีบร้อนเขาใช้เหตุการณ์ en เพื่อเรียกใช้ฟังก์ชันการเรียกกลับเมื่อโหลดสคริปต์ ดังนั้นคุณสามารถใส่รหัสทั้งหมดโดยใช้รีโมตไลบรารีในฟังก์ชันการโทรกลับ เช่น :

function loadScript(url, callback)
{
    // adding the script tag 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
});

11
ไม่สามารถเชื่อได้ว่าคำตอบนี้ถูกประเมินน้อยเกินไป ขอบคุณ.
naftalimich

2
ฉันพนันได้ว่าเป็นเพราะคนไม่ชอบอ่านบรรทัดแรกยกเว้นว่าสัญญาพวกเขาพวกเขาจะรวยถ้าพวกเขา "แค่ทำตามสามขั้นตอนลับสู่ความสำเร็จ"
Costa

วิธีนี้ใช้ได้ผล ฉันหวังว่าการแบ่งปันประสบการณ์ของฉันที่นี่จะช่วยประหยัดเวลาของคุณเพราะฉันใช้เวลาหลายชั่วโมงกับสิ่งนี้ ฉันใช้ Angular 6 และเทมเพลตที่นำไปใช้ (html, css, jquery) ปัญหาคือเทมเพลตมีไฟล์ js ซึ่งโหลดหลังจากองค์ประกอบ html ถูกโหลดเพื่อแนบเหตุการณ์ของ listeners ไฟล์ js นั้นยากต่อการดำเนินการหลังจากโหลดแอปเชิงมุมแล้ว การเพิ่มลงในแท็กสคริปต์ของแอปพลิเคชันเชิงมุม (angular.json) จะรวมไว้ แต่ไม่เรียกใช้ไฟล์ js หลังจากโหลด มันเป็นรหัสมากเกินไปที่จะเขียนใน typescript ดังนั้นนี่จึงเป็นความช่วยเหลือที่ดี ความคิดเห็นต่อไปฉันจะใส่ตัวอย่างเนื่องจากความยาวของความคิดเห็น
23918 Nour Lababidi

ฉันเพิ่งใช้รหัสนี้ดังนี้ ngAfterViewInit () {debugger; $ .getScript ("/ assets / js / jquery.app.js", function () {alert ("โหลดสคริปต์และดำเนินการ"); // ที่นี่คุณสามารถใช้ทุกอย่างที่คุณกำหนดไว้ในสคริปต์ที่โหลด}); }
Nour Lababidi

สำหรับ '$' เป็นมุมฉันได้ติดตามสิ่งนี้: stackoverflow.com/questions/32050645/…
Nour Lababidi

28

ฉันใช้เวอร์ชันที่ซับซ้อนน้อยกว่าเมื่อเร็ว ๆ นี้กับ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>

25
เยี่ยมมาก ... เว้นแต่คุณกำลังพยายามโหลด jQuery

1
ดูเหมือนว่า jQuery กำลังจะเปิดตัวในต้องใช้ปลั๊กอินใน jQuery Core สำหรับการเปิดตัวในอนาคต: plugins.jquery.com/project/require
Adam

1
เป็นวิธีที่ดียิ่งขึ้นในการใช้ jQuery $.getScriptคือการใช้งาน ดูคำตอบของฉัน
Muhd

1
Modernizr (yepnope.js) หรือ lab.js เป็นคำตอบที่เหมาะสมสำหรับสิ่งนี้ การใช้ไลบรารีสคริปต์หนา (ซึ่งต้องโหลดก่อน) ไม่ใช่คำตอบที่เหมาะสมที่สุดสำหรับมือถือหรือในสถานการณ์อื่น ๆ
1nfiniti

2
@MaulikGangani เบราว์เซอร์รุ่นเก่าและเครื่องมือตรวจสอบ html จะตีความว่าเป็นโทเค็นเพื่อสิ้นสุดสคริปต์
travis

20

โดยพื้นฐานแล้วฉันทำแบบเดียวกับที่คุณทำกับอดัม แต่ด้วยการดัดแปลงเล็กน้อยเพื่อให้แน่ใจว่าฉันผนวกท้ายแท็กหัวเพื่อทำงานให้เสร็จ ฉันเพิ่งสร้างฟังก์ชั่นรวม (รหัสด้านล่าง) เพื่อจัดการกับทั้งสคริปต์และไฟล์ 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 tag = null;
    switch( type ){
        case 'text/javascript' :
            tag = document.createElement( 'script' );
            tag.type = type;
            tag.src = url;
            break;
        case 'text/css' :
            tag = document.createElement( 'link' );
            tag.rel = 'stylesheet';
            tag.type = type;
            tag.href = url;
            break;
    }

    // Insert it to the <head> and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( tag );
    Array.add( includedFile, url );
}

หากไม่มีบริบทมากไปกว่าผักดองนั้นฉันเกรงว่าฉันไม่มีคำแนะนำ รหัสข้างต้นใช้งานได้ตามที่เป็นจริงมันถูกดึงโดยตรงจากโครงการที่ใช้งานได้
palehorse

5
@palehorse, Mike และ Muhd ​​นั้นถูกต้องมันอาจใช้ได้ในโครงการของคุณ แต่นั่นเป็นเพราะต้องมีการกำหนดตัวแปร "includedFile" และ "Array" ไว้ที่อื่นในโครงการของคุณรหัสนี้จะไม่ทำงานมันอาจจะเป็น ดีกว่าที่จะแก้ไขเพื่อให้สามารถทำงานนอกบริบทของโครงการของคุณหรืออย่างน้อยเพิ่มความคิดเห็นที่อธิบายว่าตัวแปรที่ไม่ได้กำหนดคืออะไร (ประเภท ฯลฯ )
user280109

14

อีกคำตอบที่ยอดเยี่ยม

$.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


2
ฉันจะทำอย่างไรเพื่อให้ทำงานข้ามโดเมนได้ (กำลังโหลดสคริปต์จากhttp://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
2284570

9

นี่คือตัวอย่างรหัสที่ฉันพบ ... ไม่มีใครมีวิธีที่ดีกว่า

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

ฉันจะทำอย่างไรเพื่อให้ทำงานข้ามโดเมนได้ (กำลังโหลดสคริปต์จากhttp://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
2284570

6

ถ้าคุณมี jQuery โหลดแล้วคุณควรใช้$ .getScript

นี่เป็นข้อได้เปรียบเหนือคำตอบอื่น ๆ ที่นี่เนื่องจากคุณมีฟังก์ชั่นการโทรกลับในตัว (เพื่อรับประกันว่าสคริปต์จะโหลดก่อนที่รหัสที่ขึ้นต่อกันจะทำงาน) และคุณสามารถควบคุมการแคชได้


4

หากคุณต้องการโหลดสคริปต์SYNCคุณต้องเพิ่มข้อความสคริปต์ลงในแท็ก HTML HEAD โดยตรง การเพิ่มมันจะทำให้เกิดการโหลด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()); });

3

ไม่มีใครมีวิธีที่ดีกว่า

ฉันคิดว่าการเพิ่มสคริปต์ลงในเนื้อความจะง่ายขึ้นแล้วเพิ่มลงในโหนดสุดท้ายของหน้า เกี่ยวกับสิ่งนี้:

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

ฉันจะทำอย่างไรเพื่อให้ทำงานข้ามโดเมนได้ (กำลังโหลดสคริปต์จากhttp://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
2284570

3

ผมเคยใช้วิธีอื่น ๆ ที่ผมพบในสุทธิ ... หนึ่งนี้อยู่ภายใต้ครีเอทีฟและจะตรวจสอบว่าแหล่งที่มาถูกรวมอยู่ก่อนที่จะมีการเรียกฟังก์ชั่น ...

คุณสามารถค้นหาไฟล์ได้ที่นี่: 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);
    }
  }   
} 

ฉันจะทำอย่างไรเพื่อให้ทำงานข้ามโดเมนได้ (กำลังโหลดสคริปต์จากhttp://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
2284570

3

เพิ่งค้นพบเกี่ยวกับฟีเจอร์ที่ยอดเยี่ยมในYUI 3 (ในขณะที่เขียนอยู่ในรุ่นตัวอย่าง) คุณสามารถได้อย่างง่ายดายแทรกการอ้างอิงไปยังห้องสมุด 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 ที่มีขนาดใหญ่มากสำหรับฟังก์ชั่นนี้
Muhd


2

เทคนิคที่เราใช้ในที่ทำงานคือการร้องขอไฟล์จาวาสคริปต์โดยใช้คำขอ AJAX จากนั้น eval () การคืนสินค้า หากคุณใช้ไลบรารีต้นแบบพวกเขาสนับสนุนฟังก์ชันนี้ในการโทร Ajax.Request


2

jquery แก้ไขปัญหานี้ให้ฉันด้วยฟังก์ชั่น. append () - ใช้เพื่อโหลด jquery ui package ที่สมบูรณ์

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

วิธีใช้ - ในส่วนหัวของ html / php / etc ของคุณหลังจากที่คุณนำเข้า jquery.js คุณจะรวมไฟล์นี้ไว้ในไฟล์เดียวเพื่อโหลดไลบรารีทั้งหมดของคุณต่อท้าย ...

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

2

ทำให้ดีสั้นง่ายและบำรุงรักษา! :]

// 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]);
    }
}

รหัสนี้เป็นเพียงตัวอย่างการทำงานสั้น ๆ ที่อาจต้องการฟังก์ชั่นการทำงานเพิ่มเติมสำหรับการสนับสนุนอย่างเต็มที่บนแพลตฟอร์มใด ๆ (หรือที่กำหนด)


2

แบบไดนามิกโมดูลนำเข้าที่ดินใน 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(function(){
   let times = SunCalc.getTimes(new Date(), 51.5,-0.1);
   console.log("Golden Hour today in London: " + times.goldenHour.getHours() + ':' + times.sunrise.getMinutes() + ". Take your pics!")
  })
})()

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


1

มีสคริปต์ที่ออกแบบมาโดยเฉพาะสำหรับจุดประสงค์นี้

yepnope.jsสร้างขึ้นใน Modernizr และlab.jsเป็นรุ่นที่ปรับให้เหมาะสมยิ่งขึ้น

ฉันจะไม่แนะนำให้ทำเช่นนี้ผ่านไลบรารี่ขนาดใหญ่เช่น jquery หรือ prototype เพราะหนึ่งในข้อดีที่สำคัญของ script loader คือความสามารถในการโหลดสคริปต์ก่อน - คุณไม่ควรรอจนกระทั่ง jquery & องค์ประกอบ dom ทั้งหมดของคุณโหลดมาก่อน เรียกใช้การตรวจสอบเพื่อดูว่าคุณต้องการโหลดสคริปต์แบบไดนามิกหรือไม่


1

ฉันเขียนโมดูลง่าย ๆ ที่ทำให้งานการนำเข้า / รวมถึงสคริปต์โมดูลใน JavaScript เป็นไปโดยอัตโนมัติ ลองดูและโปรดส่งข้อเสนอแนะ! :) สำหรับคำอธิบายโดยละเอียดของรหัสอ้างอิงถึงโพสต์บล็อกนี้: 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
});

1

ฉันหลงทางในตัวอย่างเหล่านี้ทั้งหมด แต่วันนี้ฉันต้องการโหลด. js ภายนอกจาก. js หลักของฉันและฉันทำสิ่งนี้:

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

คุณสามารถดูลิงค์: คำตอบ
asmmahmud

1

นี่คือง่าย ๆ ด้วยการติดต่อกลับและสนับสนุน 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');

});

1

ฉันรู้ว่าคำตอบของฉันคือบิตสายสำหรับคำถามนี้ แต่นี่เป็นบทความที่ดีในการwww.html5rocks.com - ดำน้ำลึกลงไปในน้ำมืดของการโหลดสคริปต์

ในบทความนั้นได้ข้อสรุปว่าในเรื่องการสนับสนุนเบราว์เซอร์วิธีที่ดีที่สุดในการโหลดไฟล์ JavaScript แบบไดนามิกโดยไม่ปิดกั้นการแสดงเนื้อหาเป็นวิธีต่อไปนี้:

พิจารณาว่าคุณมีสี่สคริปต์ชื่อ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 บอกว่า:ฉันไม่รู้ว่านี่คืออะไร "async" แต่มันเกิดขึ้นได้อย่างไรเมื่อฉันเรียกใช้งานสคริปต์ที่เพิ่มเข้ามาทาง JS ตามลำดับที่เพิ่มเข้ามา

Safari 5.0 กล่าวว่า:ฉันเข้าใจ“ async” แต่ไม่เข้าใจการตั้งค่าเป็น“ false” ด้วย JS ฉันจะเรียกใช้สคริปต์ของคุณทันทีที่พวกเขาถึงที่หมาย

IE <10 พูดว่า:ไม่มีความคิดเกี่ยวกับ“ async” แต่มีวิธีแก้ไขโดยใช้“ 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') {
    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"
])

ฉันใช้วิธีการข้างต้นมันทำงานได้ดีใน chrome & firefox แต่ประสบปัญหาในเบราว์เซอร์ IE
Mr. Roshan

1

บางอย่างเช่นนี้ ...

<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>

1

นี่เป็นตัวอย่างง่ายๆสำหรับฟังก์ชั่นในการโหลดไฟล์ JS จุดที่เกี่ยวข้อง:

  • คุณไม่ต้องการ jQuery ดังนั้นคุณสามารถใช้สิ่งนี้ในตอนแรกเพื่อโหลดไฟล์ jQuery.js
  • มันเป็นแบบซิงค์กับการโทรกลับ
  • มันทำให้แน่ใจว่ามันจะโหลดเพียงครั้งเดียวเนื่องจากมันเก็บกล่องหุ้มที่มีการบันทึก URL ที่โหลดดังนั้นจึงหลีกเลี่ยงการใช้เครือข่าย
  • ตรงกันข้ามกับ jQuery $.ajaxหรือคุณสามารถใช้ขณะปัจจุบันการแก้ปัญหาเกี่ยวกับการทำให้ซีเอสพี$.getScript 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");

1

ซับในที่ไร้สาระสำหรับผู้ที่คิดว่าการโหลดไลบรารี js ไม่ควรใช้โค้ดมากกว่าหนึ่งบรรทัด: P

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

แน่นอนถ้าสคริปต์ที่คุณต้องการนำเข้าเป็นโมดูลคุณสามารถใช้import(...)ฟังก์ชันได้


1

ด้วยสัญญาคุณสามารถทำให้มันง่ายขึ้นเช่นนี้ ฟังก์ชั่นโหลด:

  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
    })

การใช้งาน (async / คอย):

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

การใช้งาน (สัญญา):

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

หมายเหตุ: มีวิธีแก้ไขปัญหาที่คล้ายกัน แต่ไม่มีการตรวจสอบว่าสคริปต์โหลดแล้วและโหลดสคริปต์ทุกครั้ง อันนี้ตรวจสอบคุณสมบัติ src


0

ไลบรารี javascript ที่สำคัญทั้งหมดเช่น jscript, prototype, YUI ได้รับการสนับสนุนสำหรับการโหลดไฟล์สคริปต์ ตัวอย่างเช่นใน 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();

คุณสามารถดูลิงค์: คำตอบ
asmmahmud

0

ฉันได้ปรับแต่งโพสต์ด้านบนด้วยตัวอย่างการทำงาน ที่นี่เราสามารถให้ 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"]);
});

0

สำหรับบรรดาของคุณที่รักหนึ่งสมุทร:

import('./myscript.js');

โอกาสที่คุณอาจได้รับข้อผิดพลาดเช่น:

การเข้าถึงสคริปต์ที่ ' http: //..../myscript.js ' จากจุดเริ่มต้น ' http://127.0.0.1 ' ถูกบล็อกโดยนโยบาย CORS: ไม่มีส่วนหัว 'Access-Control-Allow-Origin' ปรากฏอยู่บน ทรัพยากรที่ร้องขอ

ในกรณีนี้คุณสามารถย้อนกลับไปที่:

fetch('myscript.js').then(r => r.text()).then(t => new Function(t)());
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.