wake-up-neo.net

So fügen Sie mehrere js-Dateien mit der jQuery $ .getScript () -Methode ein

Ich versuche, Javascript-Dateien dynamisch in meine js-Datei aufzunehmen. Ich habe etwas recherchiert und finde, dass die Methode jQuery $ .getScript () der gewünschte Weg ist.

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

Ich frage mich jedoch, ob diese Methode mehrere Skripts gleichzeitig laden kann. Warum ich das frage, ist, weil meine Javascript-Datei manchmal von mehr als einer js-Datei abhängt. 

Danke im Voraus. 

111
sozhen

Die Antwort ist

Sie können Versprechen mit getScript() verwenden und warten, bis alle Skripte geladen sind, etwa:

$.when(
    $.getScript( "/mypath/myscript1.js" ),
    $.getScript( "/mypath/myscript2.js" ),
    $.getScript( "/mypath/myscript3.js" ),
    $.Deferred(function( deferred ){
        $( deferred.resolve );
    })
).done(function(){

    //place your code here, the scripts are all loaded

});

GEIGE

EINE ANDERE FIDDLE

Im obigen Code ist das Hinzufügen eines Deferred und dessen Auflösung innerhalb von $() wie das Platzieren einer beliebigen anderen Funktion innerhalb eines jQuery-Aufrufs, wie $(func) 

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

das heißt, es wartet, bis das DOM bereit ist, und im obigen Beispiel wartet $.when darauf, dass alle Skripts geladen werden, und für das DOM wegen des $.Deferred-Aufrufs, der im DOM-ready-Rückruf aufgelöst wird.


Für den allgemeinen Gebrauch eine praktische Funktion

Eine Dienstprogrammfunktion, die ein beliebiges Array von Skripts akzeptiert, könnte folgendermaßen erstellt werden:

$.getMultiScripts = function(arr, path) {
    var _arr = $.map(arr, function(scr) {
        return $.getScript( (path||"") + scr );
    });

    _arr.Push($.Deferred(function( deferred ){
        $( deferred.resolve );
    }));

    return $.when.apply($, _arr);
}

das kann so verwendet werden

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

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

dabei wird der Pfad allen Skripts vorangestellt und ist optional, dh, wenn das Array die vollständige URL enthält, könnte dies auch der Fall sein, und der Pfad kann nicht angegeben werden

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

Argumente, Fehler usw.

Nebenbei sei bemerkt, dass der done-Callback eine Anzahl von Argumenten enthält, die mit den übergebenen Skripts übereinstimmen. Jedes Argument repräsentiert ein Array, das die Antwort enthält

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

wo jedes Array etwas wie [content_of_file_loaded, status, xhr_object]..__ enthält. Wir brauchen im Allgemeinen nicht auf diese Argumente zuzugreifen, da die Skripts sowieso automatisch geladen werden, und meistens wissen wir nur done callback Skripte wurden geladen, ich füge sie nur der Vollständigkeit halber hinzu und für den seltenen Fall, dass auf den eigentlichen Text der geladenen Datei zugegriffen werden muss oder wenn auf jedes XHR-Objekt oder ähnliches zugegriffen werden muss.

Wenn eines der Skripte nicht geladen wird, wird der Fail-Handler aufgerufen, und nachfolgende Skripts werden nicht geladen

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

Ich habe eine einfache Funktion implementiert, um mehrere Skripte parallel zu laden:

Funktion

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

Verwendungszweck

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

Laden Sie das folgende benötigte Skript in den Rückruf des vorherigen wie folgt:

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

Manchmal ist es erforderlich, Skripts in einer bestimmten Reihenfolge zu laden. Zum Beispiel muss jQuery vor der jQuery-Benutzeroberfläche geladen werden. Die meisten Beispiele auf dieser Seite laden Skripts parallel (asynchron). Dies bedeutet, dass die Reihenfolge der Ausführung nicht garantiert werden kann. Ohne Reihenfolge könnte das Skript y, das von x abhängt, brechen, wenn beide erfolgreich geladen wurden, jedoch in falscher Reihenfolge.

Ich schlage einen hybriden Ansatz vor, der das sequentielle Laden abhängiger Skripte + optionales paralleles Laden + verzögerter Objekte ermöglicht:

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

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

  return deferred;
}

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

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

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

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

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

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

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

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

Die Skripts in beiden Warteschlangen werden parallel heruntergeladen. Die Skripts in jeder Warteschlange werden jedoch nacheinander heruntergeladen, um eine geordnete Ausführung zu gewährleisten. Wasserfalldiagramm:

 waterfall chart of scripts

8
Salman A

Verwenden Sie yepnope.js oder Modernizr (das yepnope.js als Modernizr.load enthält).

UPDATE

Um es kurz zu fassen, hier ist ein gutes Äquivalent zu dem, was Sie derzeit mit yepnope verwenden, und zeigt Abhängigkeiten von mehreren Skripten auf:

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

Ich hatte eine Reihe von Problemen mit dem Laden mehrerer Skripte, wobei ein Problem auftrat, bei dem (zumindest in Chrome) dieselbe Domäne heißes Laden von Skripts ausgeführt wurde, die nach dem erfolgreichen Laden durch Ajax nicht tatsächlich ausgeführt wurden, da Cross Domain einwandfrei funktioniert. :(

Die ausgewählte Antwort auf die ursprüngliche Frage funktioniert nicht zuverlässig.

Nach vielen Iterationen hier ist meine endgültige Antwort auf GetScript (s) und das asynchrone Laden mehrerer Skripts in einer bestimmten strengen Reihenfolge mit pro Skript geladener Rückrufoption und allgemeinem Rückruf nach Abschluss, Getestet in jQuery 2.1+ und modernen Versionen von Chrome, Firefox plus aufgegeben Internet Explorer.

Mein Testfall bestand darin, Dateien für ein THREE.JS-WebGL-Rendering zu laden und dann das Render-Skript zu starten, als THREE global mit einer Intervallprüfung verfügbar wurde, die an einen anonymen Funktionsaufruf an onComplete übergeben wurde.

Die Prototypfunktion (getScripts)

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

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

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

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

Wie benutzt man

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

Die Funktion ist so, wie ich es für die Verwendung von Deferred (Deprecated now?) Gefunden habe. When, Success & Complete in meinen Versuchen, NICHT 100% zuverlässig zu sein!?, Daher diese Funktion und die Verwendung von statusCode zum Beispiel.

Wenn Sie möchten, können Sie das Verhalten bei der Fehler-/Fehlerbehandlung hinzufügen.

4
Marc Newton

Tolle Antwort, Adeneo.

Es dauerte eine Weile, bis ich herausgefunden hatte, wie ich Ihre Antwort allgemeiner formulieren konnte (damit ich ein Array von Code-definierten Skripts laden konnte). Callback wird aufgerufen, wenn alle Skripts geladen und ausgeführt wurden. Hier ist meine Lösung:

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

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

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

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

Sie können die $.when- Methode verwenden, indem Sie die folgende Funktion ausführen:

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

Diese Funktion würde folgendermaßen verwendet:

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

Das ist der Weg, Versprechungen zu verwenden und ein Minimum an Overhead zu haben.

2
Emanuel Kluge

Was Sie suchen, ist ein AMD-kompatibler Lader (wie z. B. requir.js).

http://requirejs.org/

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

Es gibt viele gute Open-Source-Programme, wenn Sie nachschlagen. Im Wesentlichen können Sie damit ein Codemodul definieren. Wenn es von anderen Codemodulen abhängig ist, wird es warten, bis diese Module vollständig heruntergeladen sind, bevor die Ausführung fortgesetzt wird. Auf diese Weise können Sie 10 Module asynchron laden, und es sollte keine Probleme geben, selbst wenn eines von einigen anderen zum Ausführen benötigt wird.

1
dqhendricks

Diese Funktion stellt sicher, dass eine Datei geladen wird, nachdem die Abhängigkeitsdatei vollständig geladen wurde. Sie müssen die Dateien nur in einer Reihenfolge bereitstellen, wobei die Abhängigkeiten von anderen Dateien berücksichtigt werden.

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

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

Das funktioniert für mich:

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

Und benutze es:

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

Hier ist die Antwort, die Maciej Sawicki eins verwendet und Promise als Callback implementiert:

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

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

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

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

Benutzen:

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

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

Alle Javascript-Dateien werden so schnell wie möglich heruntergeladen und in der angegebenen Reihenfolge ausgeführt. Dann wird taskNeedingParameters aufgerufen.

1
H4dr1en

Es gibt ein Plugin, das die getScript-Methode von jQuery erweitert. Ermöglicht asynchrones und synchrones Laden und verwendet den Caching-Mechanismus von jQuery. Vollständige Offenlegung, ich habe dies geschrieben. Bitte zögern Sie nicht, einen Beitrag zu leisten, wenn Sie eine bessere Methode finden.

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

0
user3455212

basierend auf der Antwort von @adeneo oben: Kombinieren des Ladens von CSS- und JS-Dateien

Verbesserungsvorschläge?

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

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

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

Sie können dies mit der Rekursion versuchen. Dadurch werden sie nacheinander synchron heruntergeladen, bis der Download der gesamten Liste abgeschlossen ist.

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

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

}, 0);

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

function getScript(script, callback) {
    $.getScript(script, function() {
        callback();
    });
}
0
Rick

Kürzere Version von Andrew Marc Newtons umfassender Antwort oben. Dieser prüft den Statuscode nicht auf Erfolg, was Sie tun sollten, um undefiniertes UI-Verhalten zu vermeiden. 

Dies war für ein nerviges System, bei dem ich jQuery garantieren konnte, aber kein anderes. Daher wollte ich eine Technik, die kurz genug ist, um nicht in ein externes Skript umgewandelt zu werden, wenn sie dazu gezwungen wird. (Sie könnten es noch kürzer machen, indem Sie den Index 0 an den ersten "rekursiven" Aufruf übergeben, aber die Gewohnheit der Stilgewohnheiten hat mich dazu gebracht, den Zucker hinzuzufügen).

Ich weise auch die Abhängigkeitsliste einem Modulnamen zu, so dass dieser Block überall dort eingefügt werden kann, wo Sie "module1" benötigen, und die Skripts und die abhängige Initialisierung werden nur einmal eingeschlossen/ausgeführt (Sie können index im Callback protokollieren und ein einzelnes sehen geordneter Satz von AJAX -Anfragen ausgeführt)

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

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

    var dependencies = [];

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

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

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

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

    getScriptChain(dependencies);       
}
0
Whelkaholism

Hängen Sie Skripts mit async = false an

Hier ist ein anderer, aber sehr einfacher Ansatz. Um mehrere Skripts zu laden, können Sie sie einfach an body anhängen. 

  • Lädt sie asynchron, da Browser das Laden der Seite __.page optimieren
  • Führt Skripts in der richtigen Reihenfolge aus, da Browser HTML-Tags auf diese Weise analysieren
  • Kein Rückruf erforderlich, da Skripts in der Reihenfolge ausgeführt werden. Fügen Sie einfach ein weiteres Skript hinzu und es wird nach den anderen Skripts ausgeführt

Mehr Infos hier: https://www.html5rocks.com/de/tutorials/speed/script-loading/

var scriptsToLoad = [
   "script1.js", 
   "script2.js",
   "script3.js",
]; 

scriptsToLoad.forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.body.appendChild(script);
});
0
Maciej Sawicki

Lädt n scripts eins nach dem anderen (nützlich, wenn die 2. Datei beispielsweise die 1. Datei benötigt):

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