Memuat file JavaScript secara dinamis

168

Bagaimana Anda dapat secara andal dan dinamis memuat file JavaScript? Ini akan dapat digunakan untuk mengimplementasikan modul atau komponen yang ketika 'diinisialisasi' komponen akan secara dinamis memuat semua skrip perpustakaan JavaScript yang diperlukan sesuai permintaan.

Klien yang menggunakan komponen tidak diperlukan untuk memuat semua file skrip perpustakaan (dan secara manual memasukkan <script>tag ke halaman web mereka) yang mengimplementasikan komponen ini - hanya file skrip komponen 'utama'.

Bagaimana pustaka JavaScript arus utama melakukan ini (Prototipe, jQuery, dll)? Apakah alat-alat ini menggabungkan banyak file JavaScript menjadi versi tunggal dari file skrip? Atau apakah mereka melakukan pemuatan dinamis skrip 'perpustakaan' tambahan?

Tambahan untuk pertanyaan ini: apakah ada cara untuk menangani acara setelah file JavaScript yang dimasukkan secara dinamis dimuat? Prototipe memiliki document.observeuntuk acara di seluruh dokumen. Contoh:

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

Apa saja acara yang tersedia untuk elemen skrip?

Adam
sumber

Jawaban:

84

Anda dapat menulis tag skrip dinamis (menggunakan Prototipe ):

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

Masalahnya di sini adalah kita tidak tahu kapan file skrip eksternal dimuat penuh.

Kami sering menginginkan kode dependen kami di baris berikutnya dan suka menulis sesuatu seperti:

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

Ada cara cerdas untuk menyuntikkan dependensi skrip tanpa perlu callback. Anda cukup menarik skrip melalui permintaan AJAX yang sinkron dan mengevaluasi skrip di tingkat global.

Jika Anda menggunakan Prototipe, metode Script.load terlihat seperti ini:

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);
    }
};
aemkei
sumber
Apa yang bisa saya lakukan agar berfungsi untuk lintas-domain? (memuat skrip dari http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570
@ user2284570 CORS stackoverflow.com/questions/5750696/…
Ciasto piekarz
@Ciastopiekarz: Saya tidak mengontrol web.archive.org.
user2284570
Maka Anda harus mengikis data yang ingin Anda akses menggunakan beberapa program lain dan memberikannya sendiri
David Schumann
apa itu Ajax. Permintaan ??
bluejayke
72

Tidak ada impor / sertakan / butuhkan dalam javascript, tetapi ada dua cara utama untuk mencapai apa yang Anda inginkan:

1 - Anda dapat memuatnya dengan panggilan AJAX lalu gunakan eval.

Ini adalah cara yang paling mudah tetapi terbatas pada domain Anda karena pengaturan keamanan Javascript, dan menggunakan eval membuka pintu untuk bug dan peretasan.

2 - Tambahkan tag skrip dengan URL skrip dalam HTML.

Pasti cara terbaik untuk pergi. Anda dapat memuat skrip bahkan dari server asing, dan itu bersih saat Anda menggunakan parser browser untuk mengevaluasi kode. Anda dapat meletakkan tag di bagian atas halaman web, atau di bagian bawah badan.

Kedua solusi ini dibahas dan diilustrasikan di sini.

Sekarang, ada masalah besar yang harus Anda ketahui. Melakukan hal itu menyiratkan bahwa Anda memuat kode dari jarak jauh. Browser web modern akan memuat file dan terus mengeksekusi skrip Anda saat ini karena mereka memuat semuanya secara tidak sinkron untuk meningkatkan kinerja.

Ini berarti bahwa jika Anda menggunakan trik ini secara langsung, Anda tidak akan dapat menggunakan kode yang baru dimuat di baris berikutnya setelah Anda memintanya untuk dimuat, karena masih akan memuat.

EG: my_lovely_script.js berisi 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

Kemudian Anda memuat ulang halaman yang mengenai F5. Dan itu berhasil! Membingungkan ...

Jadi apa yang harus dilakukan?

Nah, Anda dapat menggunakan retasan yang disarankan penulis di tautan yang saya berikan kepada Anda. Singkatnya, untuk orang-orang yang terburu-buru, dia menggunakan en event untuk menjalankan fungsi panggilan balik ketika skrip dimuat. Jadi Anda bisa meletakkan semua kode menggunakan pustaka jarak jauh di fungsi panggilan balik. EG:

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

Kemudian Anda menulis kode yang ingin Anda gunakan SETELAH skrip dimuat dalam fungsi lambda:

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

Kemudian Anda jalankan semua itu:

loadScript("my_lovely_script.js", myPrettyCode);

OK aku mengerti. Tetapi sulit untuk menulis semua hal ini.

Nah, dalam hal ini, Anda dapat menggunakan seperti biasa kerangka kerja jQuery gratis, yang memungkinkan Anda melakukan hal yang sama dalam satu baris:

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});
Dhaval Shah
sumber
11
tidak percaya betapa diremehkannya jawaban ini. Terima kasih.
naftalimich
2
Saya yakin itu karena orang tidak suka membaca melewati baris pertama, kecuali jika menjanjikan mereka akan kaya jika mereka "cukup ikuti tiga langkah rahasia menuju sukses."
Costa
Ini bekerja. Saya harap berbagi pengalaman saya di sini menghemat waktu Anda karena saya menghabiskan banyak waktu untuk hal ini. Saya menggunakan Angular 6 dan template yang diterapkan (html, css, jquery) Masalahnya adalah template memiliki file js yang dimuat setelah elemen html dimuat untuk melampirkan acara pendengar. File js itu sulit dieksekusi setelah aplikasi sudut dimuat. Menambahkannya ke tag skrip app sudut (angular.json) akan membundelnya tetapi tidak mengeksekusi file js setelah memuat. Terlalu banyak kode untuk ditulis ulang dalam naskah jadi ini sangat membantu. Komentar berikutnya saya akan memberikan contoh karena panjang komentar
Nour Lababidi
Saya cukup menggunakan kode ini sebagai berikut: ngAfterViewInit () {debugger; $ .getScript ("/ assets / js / jquery.app.js", function () {alert ("Script dimuat dan dieksekusi."); // di sini Anda dapat menggunakan apa pun yang Anda tetapkan dalam skrip yang dimuat}); }
Nour Lababidi
Untuk '$' dalam sudut saya ikuti ini: stackoverflow.com/questions/32050645/…
Nour Lababidi
28

Saya menggunakan versi yang jauh lebih rumit baru - baru ini dengan 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>

Ini bekerja sangat baik di setiap browser yang saya uji di: IE6 / 7, Firefox, Safari, Opera.

Pembaruan: versi 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>
travis
sumber
25
Itu bagus ... kecuali jika Anda mencoba memuat jquery.
1
Sepertinya jQuery akan bergulir di plugin Require ke jQuery Core untuk rilis mendatang: plugins.jquery.com/project/require
Adam
1
Cara yang lebih baik untuk menggunakan jQuery adalah menggunakan $.getScript. Lihat jawaban saya.
Muhd
1
Modernizr (yepnope.js) atau lab.js adalah solusi yang tepat untuk ini. menggunakan pustaka skrip yang berat (yang harus memuat lebih dulu) bukanlah jawaban yang paling cocok untuk situasi seluler atau lainnya.
1nfiniti
2
@MaulikGangani browser yang lebih lama dan validator html akan menafsirkannya sebagai token untuk mengakhiri skrip.
travis
20

Saya pada dasarnya melakukan hal yang sama seperti yang Anda lakukan pada Adam, tetapi dengan sedikit modifikasi untuk memastikan saya menambahkan tag kepala untuk menyelesaikan pekerjaan. Saya cukup membuat fungsi include (kode di bawah) untuk menangani skrip dan file css.

Fungsi ini juga memeriksa untuk memastikan bahwa skrip atau file CSS belum dimuat secara dinamis. Itu tidak memeriksa nilai-nilai kode tangan dan mungkin ada cara yang lebih baik untuk melakukan itu, tetapi melayani tujuannya.

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 );
}
kuda pucat
sumber
Tanpa lebih banyak konteks daripada itu, Pickle, aku khawatir aku tidak punya saran. Kode di atas berfungsi apa adanya, ditarik langsung dari proyek yang berfungsi.
palehorse
5
@palehorse, Mike dan Muhd, benar, mungkin berhasil di proyek Anda, tetapi itu karena variabel "IncludedFile" dan "Array" harus ditentukan di tempat lain di proyek Anda, kode ini sendiri tidak akan berjalan, mungkin saja lebih baik untuk mengeditnya sehingga dapat bekerja di luar konteks proyek Anda, atau setidaknya menambahkan komentar yang menjelaskan apa variabel yang tidak terdefinisi itu (ketik dll)
user280109
14

jawaban lain yang luar biasa

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

Naveed
sumber
2
Apa yang bisa saya lakukan agar berfungsi untuk lintas-domain? (memuat skrip dari http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570
9

Berikut ini beberapa contoh kode yang saya temukan ... apakah ada yang punya cara yang lebih baik?

  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);
  }
Adam
sumber
Apa yang bisa saya lakukan agar berfungsi untuk lintas-domain? (memuat skrip dari http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570
6

Jika Anda sudah memuat jQuery, Anda harus menggunakan $ .getScript .

Ini memiliki keunggulan dibandingkan jawaban lain di sini karena Anda memiliki fungsi panggilan balik bawaan (untuk menjamin skrip dimuat sebelum kode dependen berjalan) dan Anda dapat mengontrol caching.

Muhd
sumber
4

Jika Anda ingin memuat skrip SYNC , Anda perlu menambahkan teks skrip langsung ke tag HEAD HTML. Menambahkannya sebagai akan memicu beban ASYNC . Untuk memuat teks skrip dari file eksternal secara sinkron, gunakan XHR. Di bawah contoh cepat (ini menggunakan bagian dari jawaban lain di ini dan tulisan lainnya):

/*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()); });
Sielu
sumber
3

apakah ada yang punya cara yang lebih baik?

Saya pikir hanya menambahkan skrip ke tubuh akan lebih mudah kemudian menambahkannya ke simpul terakhir pada halaman. Bagaimana dengan ini:

function include(url) {
  var s = document.createElement("script");
  s.setAttribute("type", "text/javascript");
  s.setAttribute("src", url);
  document.body.appendChild(s);
}
Joseph Pecoraro
sumber
Apa yang bisa saya lakukan agar berfungsi untuk lintas-domain? (memuat skrip dari http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570
3

Saya telah menggunakan solusi lain yang saya temukan di internet ... yang satu ini di bawah creativecommons dan memeriksa apakah sumbernya dimasukkan sebelum memanggil fungsi ...

Anda dapat menemukan file di sini: include.js

/** include - including .js files from JS - [email protected] - 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);
    }
  }   
} 
Pierre Spring
sumber
Apa yang bisa saya lakukan agar berfungsi untuk lintas-domain? (memuat skrip dari http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570
3

Baru tahu tentang fitur hebat di YUI 3 (pada saat penulisan tersedia dalam rilis pratinjau). Anda dapat dengan mudah memasukkan dependensi ke perpustakaan YUI dan ke modul "eksternal" (apa yang Anda cari) tanpa terlalu banyak kode: YUI Loader .

Ini juga menjawab pertanyaan kedua Anda mengenai fungsi yang dipanggil segera setelah modul eksternal dimuat.

Contoh:

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

Bekerja dengan sempurna untuk saya dan memiliki keuntungan mengelola dependensi. Lihat dokumentasi YUI untuk contoh dengan kalender YUI 2 .

Kariem
sumber
Ini mungkin ideal kecuali untuk YUI yang sangat besar hanya untuk fungsi ini.
Muhd
3

Ada standar ECMA baru yang diusulkan yang disebut impor dinamis , baru-baru ini dimasukkan ke Chrome dan Safari.

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

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

Teknik yang kami gunakan di tempat kerja adalah meminta file javascript menggunakan permintaan AJAX dan kemudian eval () kembali. Jika Anda menggunakan pustaka prototipe, mereka mendukung fungsi ini dalam panggilan Ajax.Request mereka.

17 dari 26
sumber
2

jquery menyelesaikan ini untuk saya dengan fungsi .append () - gunakan ini untuk memuat paket jquery ui lengkap

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

Untuk Menggunakan - di kepala html / php / etc Anda setelah Anda mengimpor jquery.js Anda hanya akan memasukkan file yang satu ini seperti itu untuk memuat keseluruhan perpustakaan Anda menambahkannya ke kepala ...

<script type="text/javascript" src="project.library.js"></script>
Desain JM
sumber
2

Tetap bagus, pendek, sederhana, dan dapat dipelihara! :]

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

Kode ini hanyalah contoh fungsional singkat yang dapat memerlukan fungsionalitas fitur tambahan untuk dukungan penuh pada platform apa pun (atau yang diberikan).

tfont
sumber
2

Impor modul dinamis mendarat di Firefox 67+ .

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

Dengan penanganan kesalahan:

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

Ini juga berfungsi untuk semua jenis perpustakaan non-modul, dalam hal ini lib tersedia pada objek jendela, cara lama, tetapi hanya sesuai permintaan, yang bagus.

Contoh menggunakan suncalc.js , server harus mengaktifkan CORS agar berfungsi seperti ini!

(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

NVRM
sumber
1

Ada skrip yang dirancang khusus untuk tujuan ini.

yepnope.js dibangun ke dalam Modernizr, dan lab.js adalah versi yang lebih dioptimalkan (tetapi kurang ramah pengguna.

Saya tidak akan merekomendasikan melakukan ini melalui perpustakaan besar seperti jquery atau prototipe - karena salah satu manfaat utama dari pemuat skrip adalah kemampuan untuk memuat skrip lebih awal - Anda tidak perlu menunggu sampai jquery & semua elemen dom Anda dimuat sebelum menjalankan pemeriksaan untuk melihat apakah Anda ingin memuat skrip secara dinamis.

1nfiniti
sumber
1

Saya menulis modul sederhana yang mengotomatiskan pekerjaan mengimpor / termasuk skrip modul dalam JavaScript. Cobalah dan silakan berikan umpan balik! :) Untuk penjelasan rinci tentang kode, lihat posting blog ini: 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
});
stamat
sumber
1

Saya kehilangan semua sampel ini, tetapi hari ini saya perlu memuat .js eksternal dari .js utama saya dan saya melakukan ini:

document.write("<script src='https://www.google.com/recaptcha/api.js'></script>");
adrianTNT
sumber
Anda dapat melihat tautannya: answer
asmmahmud
1

Inilah yang sederhana dengan dukungan callback dan 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');

});
Yakub
sumber
1

Saya tahu jawaban saya agak terlambat untuk pertanyaan ini, tetapi, di sini ada artikel bagus di www.html5rocks.com - Menyelam dalam-dalam ke perairan keruh pemuatan skrip .

Dalam artikel itu disimpulkan bahwa dalam hal dukungan browser, cara terbaik untuk secara dinamis memuat file JavaScript tanpa memblokir rendering konten adalah dengan cara berikut:

Mengingat Anda memiliki empat skrip bernama script1.js, script2.js, script3.js, script4.jsmaka Anda dapat melakukannya dengan menerapkan 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);
});

Sekarang, Spec mengatakan : Unduh bersama, jalankan segera setelah semua unduhan.

Firefox <3.6, Opera mengatakan: Saya tidak tahu apa itu "async" itu, tetapi kebetulan saya mengeksekusi skrip yang ditambahkan melalui JS sesuai urutan penambahannya.

Safari 5.0 mengatakan: Saya mengerti "async", tetapi tidak mengerti pengaturannya ke "false" dengan JS. Saya akan menjalankan skrip Anda segera setelah mereka mendarat, dalam urutan apa pun.

IE <10 mengatakan: Tidak tahu tentang "async", tetapi ada solusi menggunakan "onreadystatechange".

Yang lainnya mengatakan: Aku temanmu, kita akan melakukan ini berdasarkan buku.

Sekarang, kode lengkap dengan solusi 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>');
  }
}

Beberapa trik dan minifikasi kemudian, 362 byte

!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"
])
asmmahmud
sumber
Saya menggunakan pendekatan di atas bekerja dengan baik di chrome & firefox tetapi menghadapi masalah di browser IE
Tn. Roshan
1

Sesuatu seperti ini...

<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>
James Arnold
sumber
1

Berikut contoh sederhana untuk fungsi memuat file JS. Poin yang relevan:

  • Anda tidak perlu jQuery, jadi Anda dapat menggunakan ini awalnya untuk memuat juga file jQuery.js
  • itu async dengan panggilan balik
  • itu memastikan hanya memuat satu kali, karena menyimpan lampiran dengan catatan url yang dimuat, sehingga menghindari penggunaan jaringan
  • bertentangan dengan jQuery $.ajaxatau $.getScriptAnda dapat menggunakan nonces, dengan demikian menyelesaikan masalah dengan CSP unsafe-inline. Cukup gunakan propertiscript.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);
        }
    };
}();

Sekarang Anda menggunakannya hanya dengan

getScriptOnce("url_of_your_JS_file.js");
João Pimentel Ferreira
sumber
1

Satu baris yang absurd, bagi mereka yang berpikir bahwa memuat perpustakaan js tidak boleh mengambil lebih dari satu baris kode: 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)});

Jelas jika skrip yang ingin Anda impor adalah modul, Anda dapat menggunakan import(...)fungsinya.


sumber
1

Dengan Janji Anda dapat menyederhanakannya seperti ini. Fungsi pemuat:

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

Penggunaan (async / menunggu):

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

Penggunaan (Janji):

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

CATATAN: ada satu solusi serupa tetapi tidak memeriksa apakah skrip sudah dimuat dan memuat skrip setiap kali. Yang ini memeriksa properti src.

radulle
sumber
0

semua pustaka javascript utama seperti jscript, prototype, YUI memiliki dukungan untuk memuat file skrip. Misalnya, di YUI, setelah memuat inti Anda dapat melakukan hal berikut untuk memuat kontrol kalender

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();
Darren Kopp
sumber
Anda dapat melihat tautannya: answer
asmmahmud
0

Saya telah men-tweak beberapa posting di atas dengan contoh kerja. Di sini kita bisa memberikan css dan js dalam array yang sama juga.

$(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"]);
});
VG P
sumber
0

Bagi Anda, yang menyukai one-liners:

import('./myscript.js');

Kemungkinannya Anda mungkin mendapatkan kesalahan, seperti:

Akses ke skrip di ' http: //..../myscript.js ' from origin ' http://127.0.0.1 ' telah diblokir oleh kebijakan CORS: Tidak ada tajuk 'Access-Control-Allow-Origin' hadir di sumber daya yang diminta.

Dalam hal ini, Anda dapat mundur ke:

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