javascript - pure - loadscript multiple




Comment inclure plusieurs fichiers js à l'aide de la méthode jQuery $.getScript() (12)

J'essaie d'inclure dynamiquement des fichiers javascript dans mon fichier js. J'ai fait des recherches à ce sujet et j'ai trouvé que la méthode $ .getScript () de jQuery serait un bon choix.

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

Mais je me demande si cette méthode peut charger plusieurs scripts en même temps? Pourquoi je demande c'est parce que parfois mon fichier javascript dépend de plus d'un fichier js.

Merci d'avance.


Ajouter des scripts avec async = false

Voici une approche différente, mais super simple. Pour charger plusieurs scripts, vous pouvez simplement les ajouter au corps.

  • Les charge de manière asynchrone, car c'est ainsi que les navigateurs optimisent le chargement de la page
  • Exécute les scripts dans l'ordre, car c'est ainsi que les navigateurs analysent les balises HTML
  • Pas besoin de callback, car les scripts sont exécutés dans l'ordre. Ajoutez simplement un autre script, et il sera exécuté après les autres scripts

Plus d'infos ici: https://www.html5rocks.com/en/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);
});

La réponse est

Vous pouvez utiliser des promesses avec getScript() et attendre que tous les scripts soient chargés, quelque chose comme:

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

});

FIDDLE

UNE AUTRE FIDDLE

Dans le code ci-dessus, ajouter un différé et le résoudre dans $() revient à placer n'importe quelle autre fonction dans un appel jQuery, comme $(func) , c'est la même chose que

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

c'est-à-dire qu'il attend que le DOM soit prêt, donc dans l'exemple ci-dessus, $.when attend que tous les scripts soient chargés et que le DOM soit prêt à cause de l'appel $.Deferred qui résout dans le rappel DOM ready.

Pour une utilisation plus générique, une fonction pratique

Une fonction d'utilité qui accepte n'importe quel tableau de scripts pourrait être créée comme ceci:

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

qui peut être utilisé comme ça

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

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

où le chemin sera préfixé à tous les scripts, et est également facultatif, ce qui signifie que si le tableau contient l'URL complète on pourrait aussi faire cela, et laisser le chemin tous ensemble

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

Arguments, erreurs etc.

En aparté, notez que le rappel done contiendra un nombre d'arguments correspondant aux scripts passés, chaque argument représentant un tableau contenant la réponse

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

où chaque tableau contiendra quelque chose comme [content_of_file_loaded, status, xhr_object] . Nous n'avons généralement pas besoin d'accéder à ces arguments car les scripts seront automatiquement chargés de toute façon, et la plupart du temps le rappel done est tout ce que nous voulons vraiment savoir que tous les scripts ont été chargés, je l'ajoute juste pour l'exhaustivité, et pour les rares occasions où le texte réel du fichier chargé doit être consulté, ou quand on a besoin d'accéder à chaque objet XHR ou quelque chose de similaire.

En outre, si l'un des scripts ne se charge pas, le gestionnaire d'échec sera appelé et les scripts suivants ne seront pas chargés

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

Ce que vous cherchez est un chargeur compatible AMD (comme require.js).

http://requirejs.org/

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

Il y a beaucoup de bonnes sources open source si vous le cherchez. Fondamentalement cela vous permet de définir un module de code, et s'il dépend d'autres modules de code, il attendra que ces modules aient fini de télécharger avant de continuer à fonctionner. De cette façon, vous pouvez charger 10 modules de façon asynchrone et il ne devrait pas y avoir de problèmes même si l'un dépend de quelques autres.


Cela fonctionne pour moi:

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

Et utilisez-le:

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

Charge n scripts un par un (utile si par exemple le 2ème fichier nécessite le 1er):

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

Chargez le script suivant nécessaire dans le rappel du précédent comme:

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

J'ai implémenté une fonction simple pour charger plusieurs scripts en parallèle:

Fonction

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

Usage

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

J'ai rencontré un certain nombre de problèmes avec le chargement de plusieurs scripts inculnant un problème avec (même au moins dans Chrome) le même chargement à chaud de scripts qui ne sont pas réellement lancés après avoir été chargés avec succès par Ajax où Cross Domain fonctionne parfaitement! :(

La réponse sélectionnée à la question initiale ne fonctionne pas de manière fiable.

Après beaucoup d'itérations voici ma réponse finale à getScript (s) et de charger plusieurs scripts de manière asynchrone dans un ordre strict spécifique avec l'option callback chargée par script et le callback final, Tested in jQuery 2.1+ et les versions modernes de Chrome, Firefox et Internet Explorer abandonné.

Mon scénario de test chargeait des fichiers pour un rendu webGL THREE.JS puis démarrait le script de rendu lorsque THREE global devenait disponible en utilisant une vérification d'intervalle passée à un appel de fonction anonyme à onComplete.

La fonction Prototype (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();
};

Comment utiliser

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

La fonction est telle que je l'ai trouvé en utilisant différé (déprécié maintenant?), Quand, succès et complet dans mes essais pour ne pas être fiable à 100%!?, D'où cette fonction et l'utilisation de statusCode par exemple.

Vous pouvez ajouter un comportement de gestion erreur / échec si vous le souhaitez.


Utilisez yepnope.js ou Modernizr (qui inclut yepnope.js comme Modernizr.load ).

METTRE À JOUR

Juste pour le suivi, voici un bon équivalent de ce que vous avez actuellement en utilisant yepnope, montrant les dépendances sur plusieurs scripts:

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

Version plus courte de la réponse complète d'Andrew Marc Newton ci-dessus. Celui-ci ne vérifie pas le code d'état du succès, ce que vous devez faire pour éviter un comportement d'interface utilisateur non défini.

Celui-ci était pour un système ennuyeux où je pourrais garantir jQuery mais aucun autre inclut, ainsi j'ai voulu une technique assez courte pour ne pas être cultivée dans un manuscrit externe si forcé dedans. (Vous pourriez le rendre encore plus court en passant l'index 0 au premier appel "récursif" mais la force des habitudes de style m'a fait ajouter le sucre).

J'attribue également la liste des dépendances à un nom de module, ce bloc peut donc être inclus partout où vous avez besoin de "module1" et les scripts et l'initialisation dépendante ne seront inclus / exécutés qu'une fois (vous pouvez enregistrer l' index dans le rappel et voir un seul ensemble ordonné de demandes AJAX runnning)

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

Vous pouvez utiliser le $.when .when -method en essayant la fonction suivante:

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

Cette fonction serait utilisée comme ceci:

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

C'est la façon d'utiliser Promises et d'avoir un minimum de frais généraux.


basé sur la réponse de @adeneo ci-dessus: Combinant à la fois le chargement des fichiers css et js

des suggestions d'améliorations?

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




promise