Bir JavaScript dosyasını dinamik olarak yükleyin


168

Bir JavaScript dosyasını nasıl güvenilir ve dinamik olarak yükleyebilirsiniz? Bu, 'başlatıldığında' bileşen gerekli tüm JavaScript kitaplığı komut dosyalarını isteğe bağlı olarak dinamik olarak yükleyecek bir modül veya bileşen uygulamak için kullanılabilir.

Bileşeni kullanan istemcinin, bu bileşeni uygulayan tüm kitaplık komut dosyası dosyalarını (ve <script>web sayfalarına el ile etiket eklemesi) yüklemesi gerekmez - yalnızca 'ana' bileşen komut dosyası.

Genel JavaScript kütüphaneleri bunu nasıl başarır (Prototip, jQuery, vb.)? Bu araçlar, birden fazla JavaScript dosyasını komut dosyasının tek bir yeniden dağıtılabilir 'derleme' sürümünde birleştiriyor mu? Veya yardımcı 'kütüphane' komut dosyalarının dinamik yüklemesini yapıyorlar mı?

Bu soruya ek olarak: dinamik olarak dahil edilen bir JavaScript dosyası yüklendikten sonra etkinliği işlemenin bir yolu var mı? Prototip, document.observebelge çapında etkinlikler için vardır. Misal:

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

Bir komut dosyası öğesi için kullanılabilir olaylar nelerdir?


Yanıtlar:


84

Dinamik komut dosyası etiketleri yazabilirsiniz ( Prototip kullanarak ):

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

Buradaki sorun , harici komut dosyasının tam olarak ne zaman yüklendiğini bilmememizdir .

Genellikle bağımlı kodumuzu bir sonraki satırda istiyoruz ve şöyle bir şey yazmak istiyoruz:

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

Geri çağırma gereksinimi olmadan komut dosyası bağımlılıklarını enjekte etmenin akıllı bir yolu vardır. Senaryoyu senkronize bir AJAX isteğiyle çekmeniz ve betiği global düzeyde değerlendirmeniz yeterlidir .

Prototip kullanırsanız Script.load yöntemi şöyle görünür:

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

Web alanları arası için çalışmasını sağlamak için ne yapabilirim? (komut dosyası yükleniyor http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570


@Ciastopiekarz: Kontrol etmiyorum web.archive.org.
user2284570

Sonra başka bir program kullanarak erişmek istediğiniz verileri kazımak ve kendinize sağlamak zorundasınız
David Schumann

Ajax.Request nedir?
bluejayke

72

Javascript'te içe aktarma / dahil etme / gereksinim yok, ancak istediğinizi elde etmenin iki ana yolu var:

1 - Bir AJAX çağrısı ile yükleyebilir ve eval kullanabilirsiniz.

Bu en basit yoldur, ancak Javascript güvenlik ayarları nedeniyle alan adınızla sınırlıdır ve eval kullanımı hatalara ve saldırılara kapı açmaktadır.

2 - HTML'de komut dosyası URL'sini içeren bir komut dosyası etiketi ekleyin.

Kesinlikle gitmek için en iyi yol. Komut dosyasını yabancı bir sunucudan bile yükleyebilirsiniz ve kodu değerlendirmek için tarayıcı ayrıştırıcısını kullandığınızda temizdir. Etiketi web sayfasının başına veya gövdenin altına yerleştirebilirsiniz.

Bu çözümlerin her ikisi de burada tartışılmış ve gösterilmiştir.

Şimdi bilmeniz gereken büyük bir sorun var. Bunu yapmak, kodu uzaktan yüklediğiniz anlamına gelir. Modern web tarayıcıları dosyayı yükler ve mevcut komut dosyanızı yürütmeye devam eder, çünkü performanslarını artırmak için her şeyi eşzamansız olarak yüklerler.

Bu, bu hileleri doğrudan kullanırsanız, yüklenmesini istedikten sonra yeni yüklediğiniz kodu bir sonraki satırda kullanamayacağınız anlamına gelir, çünkü yine de yüklenecektir.

EG: my_lovely_script.js MySuperObject içeriyor

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

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

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

Sonra F5 tuşuna basarak sayfayı yeniden yüklersiniz. Ve çalışıyor! Kafa karıştırıcı...

Peki bu konuda ne yapmalı?

Yazarın size verdiğim linkte önerdiği hack'i kullanabilirsiniz. Özetle, acelesi olan kişiler için, komut dosyası yüklendiğinde en olayı geri arama işlevini çalıştırmak için kullanır. Böylece tüm kodu geri çağrı işlevindeki uzak kitaplığı kullanarak koyabilirsiniz. ÖRNEĞİN :

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

Sonra komut dosyası lambda işlevinde yüklendikten SONRA kullanmak istediğiniz kodu yazarsınız:

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

Sonra tüm bunları çalıştırın:

loadScript("my_lovely_script.js", myPrettyCode);

Tamam anladım. Ama bütün bunları yazmak acı verici.

Bu durumda, her zaman olduğu gibi aynı şeyi tek bir satırda yapmanıza izin veren fantastik ücretsiz jQuery çerçevesini kullanabilirsiniz:

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

11
bu cevabın ne kadar önemsiz olduğuna inanamıyorum. Teşekkür ederim.
naftalimich

2
Bahse girerim çünkü insanlar ilk satırı okumayı sevmezler, onlara söz vermedikçe "başarı için bu üç gizli adımı izlerse" zengin olurlar.
Costa

Bu çalışıyor. Umarım burada deneyimlerimi paylaşmak zaman kazandırır çünkü bunun için uzun saatler harcadım. Açısal 6 ve uygulanan şablonu (html, css, jquery) kullanıyorum Sorun şablon html öğeleri dinleyici olayları eklemek için yüklendikten sonra yüklenen bir js dosyası olmasıdır. Açısal uygulama yüklendikten sonra bu js dosyasının yürütülmesi zordu. Açısal app (angular.json) komut dosyaları etiketine eklenmesi, bunları paketleyecek ancak yükledikten sonra bu js dosyasını yürütmeyecektir. Daktiloda yeniden yazmak için çok fazla kod bu yüzden bu çok yardımcı oldu. Sonraki yorum Yorum uzunluğu nedeniyle örnek koyacağım
Nour Lababidi

Ben sadece bu kodu aşağıdaki gibi kullandım: ngAfterViewInit () {debugger; $ .getScript ("/ asset / js / jquery.app.js", function () {alert ("Komut dosyası yüklendi ve yürütüldü."); // burada yüklenen komut dosyasında tanımladığınız her şeyi kullanabilirsiniz}); }
Nour Lababidi


28

Son zamanlarda jQuery ile çok daha az karmaşık bir sürüm kullandım :

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

Test ettiğim her tarayıcıda harika çalıştı: IE6 / 7, Firefox, Safari, Opera.

Güncelleme: jQuery'siz sürüm:

<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
Bu harika ... jquery yüklemeye çalışmadığınız sürece.

1
Görünüşe göre jQuery, Gelecek bir sürüm için Require eklentisini jQuery Core'a taşıyacak: plugins.jquery.com/project/require
Adam

1
JQuery kullanmanın daha iyi bir yolu kullanmaktır $.getScript. Cevabımı gör.
Muhd

1
Modernizr (yepnope.js) veya lab.js bunun için uygun çözümlerdir. (önce yüklenmesi gereken) bir ağır komut dosyası kitaplığı kullanmak, mobil veya diğer birçok durum için en uygun yanıt değildir.
1nfiniti

2
@MaulikGangani eski tarayıcılar ve html doğrulayıcıları bunu betiği sonlandırmak için belirteç olarak yorumlayacaktı.
travis

20

Temel olarak Adam'la aynı şeyi yaptım, ama işi yapmak için kafa etiketine eklediğimden emin olmak için hafif bir değişiklikle. Ben sadece hem script hem de css dosyalarını işlemek için bir dahil fonksiyon (aşağıdaki kod) yarattı.

Bu işlev ayrıca komut dosyasının veya CSS dosyasının önceden dinamik olarak yüklenmediğinden emin olunmasını denetler. El kodlu değerleri kontrol etmez ve bunu yapmanın daha iyi bir yolu olabilir, ancak amaca hizmet etti.

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

O turşudan daha fazla bağlam olmadan, korkarım herhangi bir öneri yok. Yukarıdaki kod olduğu gibi çalışır, doğrudan çalışan bir projeden alınmıştır.
solgunluk

5
@palehorse, Mike ve Muhd, haklısın, projenizde işe yarayabilir, ancak bu "projeninDosyası" ve "Dizi" değişkenlerinin projenizde başka bir yerde tanımlanması gerektiğinden, bu kod kendi başına çalışmaz, daha iyi düzenlemek için projenizin bağlamı dışında çalışabilir veya en azından tanımlanmamış değişkenlerin ne olduğunu açıklayan bir yorum ekleyebilirsiniz (tip vb.)
user280109

14

başka bir harika cevap

$.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
Web alanları arası için çalışmasını sağlamak için ne yapabilirim? (komut dosyası yükleniyor http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

9

Bulduğum bazı örnek kod ... daha iyi bir yolu var mı?

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

Web alanları arası için çalışmasını sağlamak için ne yapabilirim? (komut dosyası yükleniyor http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

6

Zaten jQuery yüklüyse, $ .getScript kullanmalısınız .

Bunun, diğer geri arama işlevine sahip olmanız (betiğin bağımlı kod çalıştırmadan önce yüklenmesini sağlamak için) ve önbelleğe almayı kontrol edebilmeniz açısından diğer yanıtlara göre bir avantajı vardır.


4

Bir SYNC komut dosyası yüklemesi istiyorsanız, komut dosyası metnini doğrudan HTML HEAD etiketine eklemeniz gerekir. Olarak eklemek bir ASYNC yükünü tetikleyecektir . Harici dosyadan komut dosyası metnini eşzamanlı olarak yüklemek için XHR'yi kullanın. Hızlı bir örnek altında (bu ve diğer yayınlardaki diğer cevapların bölümlerini kullanıyor):

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

daha iyi bir yolu var mı?

Ben sadece vücuda komut dosyası eklemek daha sonra sayfadaki son düğüme eklemek daha kolay olacağını düşünüyorum. Buna ne dersin:

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

Web alanları arası için çalışmasını sağlamak için ne yapabilirim? (komut dosyasını yükleme http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

3

i net buldum başka bir çözüm kullandım ... Bu creativecommons altında ve işlevi çağırmadan önce kaynak dahil olup olmadığını kontrol eder ...

dosyayı burada bulabilirsiniz: 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);
    }
  }   
} 

Web alanları arası için çalışmasını sağlamak için ne yapabilirim? (komut dosyası yükleniyor http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

3

YUI 3'teki harika bir özellik hakkında yeni bilgi edindim (önizleme sürümünde yazı yazılırken). YUI kitaplıklarına ve "harici" modüllere (aradığınızı) çok fazla kod kullanmadan kolayca bağımlılıklar ekleyebilirsiniz: YUI Yükleyici .

Harici modül yüklenir yüklenmez çağrılan işleve ilişkin ikinci sorunuza da yanıt verir.

Misal:

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

Benim için mükemmel çalıştı ve bağımlılıkları yönetme avantajına sahip. YUI 2 takvimiyle ilgili bir örnek için YUI belgelerine bakın .


Bu, YUI'nin sadece bu işlevsellik için çok büyük olması dışında muhtemelen idealdir.
Muhd

3

Yakın zamanda Chrome ve Safari'ye dahil edilen dinamik içe aktarma adı verilen yeni bir ECMA standardı var .

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

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

2

İş yerinde kullandığımız teknik, bir AJAX isteği kullanarak javascript dosyasını istemek ve ardından dönüşü değerlendirmektir (). Prototip kitaplığını kullanıyorsanız, Ajax.Request çağrılarında bu işlevi desteklerler.


2

jquery .append () işleviyle bunu benim için çözdü - bunu jquery ui paketinin tamamını yüklemek için kullandı

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

Kullanmak için - jquery.js'yi içe aktardıktan sonra html / php / etc'nizin başına, kitaplığınızın başına ekleyerek tamamen yüklemek için böyle bir dosya eklersiniz ...

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

2

Güzel, kısa, basit ve bakımı kolay! :]

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

Bu kod sadece kısa bir işlevsel örnektir olabilir herhangi tam destek (veya verilen) platformu için ek özellik işlevselliğini gerektirir.


2

Dinamik modül içe aktarımı Firefox 67+ sürümüne indi .

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

Hata yönetimi ile:

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

Modül olmayan kütüphaneler için de çalışır, bu durumda lib pencere nesnesinde eski yolla kullanılabilir, ancak sadece talep üzerine, bu güzel.

Suncalc.js kullanan örnekte , sunucunun bu şekilde çalışması için CORS etkinleştirilmiş olmalıdır !

(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

Bu amaç için özel olarak tasarlanmış komut dosyaları vardır.

yepnope.js Modernizr'de yerleşiktir ve lab.js daha optimize (ancak daha az kullanıcı dostu bir sürüm).

Bunu jquery veya prototip gibi büyük bir kütüphane aracılığıyla önermem - bir script yükleyicinin en büyük avantajlarından biri komut dosyalarını erken yükleme yeteneğidir - jquery ve tüm dom öğeleriniz daha önce yüklenene kadar beklemek zorunda kalmamalısınız bir betiği dinamik olarak yüklemek isteyip istemediğinizi görmek için bir kontrol gerçekleştirin.


1

JavaScript'e modül komut dosyaları alma / dahil etme işini otomatikleştiren basit bir modül yazdım. Bir deneyin ve lütfen geri bildirimde bulunun! :) Kodun ayrıntılı açıklaması için bu blog gönderisine bakın: 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

Tüm bu örneklerde kayboldum ama bugün ana .js'den harici bir .js yüklemem gerekiyordu ve bunu yaptım:

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

bağlantıya bir göz atabilirsiniz: answer
asmmahmud

1

İşte geri arama ve IE desteği ile basit bir tane:

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

Cevabımın bu soru için biraz geç olduğunu biliyorum, ama burada www.html5rocks.com harika bir makale var - Senaryo yükleme karanlık sularına derin dalış .

Bu makalede, tarayıcı desteği ile ilgili olarak, içerik oluşturmayı engellemeden JavaScript dosyasını dinamik olarak yüklemenin en iyi yolunun şu şekilde olduğu sonucuna varılmıştır:

Adında dört komut dosyanız olduğunu göz önünde bulundurarak script1.js, script2.js, script3.js, script4.js, async = false uygulayarak yapabilirsiniz :

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

Şimdi, Spec diyor ki : Birlikte indirin, en kısa sürede sırayla çalıştırın.

Firefox <3.6, Opera diyor ki: Bu “eşzamansız” şeyin ne olduğu hakkında hiçbir fikrim yok, ancak JS ile eklenen komut dosyalarını eklendikleri sırayla yürütüyorum.

Safari 5.0 diyor: “async” i anlıyorum, ancak JS ile “false” olarak ayarlamayı anlamıyorum. Senaryolarınızı iner inmez, hangi sırayla uygulayacağım.

IE <10 diyor: “zaman uyumsuz” hakkında bir fikrim yok ama “onreadystatechange” kullanarak bir çözüm var.

Diğer her şey diyor ki: Ben senin arkadaşınım, bunu kitapla yapacağız.

Şimdi, IE <10 geçici çözümüyle tam kod:

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

Birkaç hile ve küçültme sonra 362 bayt

!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"
])

Yukarıdaki yaklaşımı kullanıyorum, krom ve firefox'ta iyi çalışıyor ancak IE tarayıcısında sorunlarla karşı karşıya
Bay Roshan

1

Böyle bir şey ...

<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

Burada JS dosyalarını yüklemek için bir işlev için basit bir örnek. İlgili noktalar:

  • jQuery'ye ihtiyacınız yoktur, bu nedenle başlangıçta jQuery.js dosyasını da yüklemek için kullanabilirsiniz.
  • geri arama ile zaman uyumsuz
  • yüklü URL'lerin kaydına sahip bir kasayı sakladığından yalnızca bir kez yüklenmesini sağlar, böylece ağın kullanılmasını önler
  • jQuery aksine $.ajaxveya $.getScriptCSP ile sorunları çözerek nonces kullanabilirsiniz unsafe-inline. Sadece özelliği kullanınscript.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);
        }
    };
}();

Şimdi sadece

getScriptOnce("url_of_your_JS_file.js");

1

Bir js kütüphanesinin yüklenmesinin birden fazla kod satırı almaması gerektiğini düşünenler için saçma bir astar.

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

Açıkçası, içe aktarmak istediğiniz komut dosyası bir modülse, import(...)işlevi kullanabilirsiniz .


1

Promises ile bunu basitleştirebilirsiniz. Yükleyici fonksiyonu:

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

Kullanım (zaman uyumsuz / beklemede):

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

Kullanımı (Söz):

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

NOT: benzer bir çözüm vardı, ancak komut dosyasının önceden yüklenmiş olup olmadığını kontrol etmez ve her seferinde komut dosyasını yükler. Bu src özelliğini kontrol eder.


0

jscript, prototip, YUI gibi tüm büyük javascript kütüphanelerinin kod dosyalarını yükleme desteği vardır. Örneğin, YUI'de, çekirdeği yükledikten sonra takvim denetimini yüklemek için aşağıdakileri yapabilirsiniz

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

bağlantıya bir göz atabilirsiniz: answer
asmmahmud

0

Yukarıdaki yazının bazılarını çalışma örneği ile değiştirdim. Burada aynı dizide css ve js de verebiliriz.

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

Tek gömlekleri sevenler için:

import('./myscript.js');

Muhtemelen aşağıdaki gibi bir hata alabilirsiniz:

En senaryoya Erişim ' : http //..../myscript.js kökenli' ' http://127.0.0.1 ' CORS politikası tarafından bloke edilmiştir: Hayır 'Erişim-Control-Allow-Origin' başlığı mevcut olduğunu istenen kaynak.

Bu durumda, aşağıdakilere geri dönebilirsiniz:

fetch('myscript.js').then(r => r.text()).then(t => new Function(t)());
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.