J'ai plusieurs scripts à inclure dynamiquement dans un ordre spécifique. J'ai regardé et essayé plusieurs réponses ici: Comment faire inclure plusieurs fichiers js en utilisant la méthode jQuery $ .getScript ()
Mon problème est que les réponses ici ne fonctionnent pas dans mon application en raison du chargement des fichiers de manière asynchrone ou compliquent considérablement le problème en raison du chargement externe scripts. Les scripts que j'ai besoin de charger dynamiquement sont internes. (ie: Sur le serveur de mon site)
En plus de nombreuses autres tentatives, j'ai essayé:
$.when(
$.getScript('/1.js'),
$.getScript('/2.js'),
$.getScript('/3.js'),
$.getScript('/4.js'),
$.getScript('/5.js'),
$.Deferred(function (deferred) {
$(deferred.resolve);
})
).done(function() {
//Do Something
});
mais cela ne charge pas les scripts dans le bon ordre et élimine un grand nombre d'erreurs.
De plus, les scripts que je dois charger sont internes et je ne vois pas le besoin de tous les AJAX
J'ai également essayé d'autres variantes en vain et espérait que quelqu'un pourrait illustrer comment je pourrais charger dynamiquement des scripts internes les uns après les autres, de préférence sans appels AJAX et trop compliquer?
3 Réponses :
getScript renvoie un objet de type Promise, vous pouvez donc attendre chaque appel de celui-ci dans une boucle pour qu'ils soient traités en série:
(async () => {
for (const path of ['/1.js', '/2.js', '/3.js']) {
await $.getScript(path);
}
// Do something
})()
.catch((err) => {
// Something went wrong
});
Je vous remercie infiniment. Pourrais-je vous intéresser à emballer cela de la même manière que le script $ .when (... que j'ai posté? Je ne sais pas comment comprendre: "(async () => {" et pouvoir faire un pas
await ne peut être utilisé que dans une fonction async , donc async et IIFE. Les fonctions asynchrones renvoient des promesses, et la promesse rejettera si l'un des éléments attendus à l'intérieur de la fonction est rejeté, donc .catch est nécessaire à l'extérieur pour gérer les erreurs. Vous pouvez également utiliser try / catch à l'intérieur de l'IIFE en attendant, mais .catch ( ing the Promise semble beaucoup plus agréable IMO. Vous n'avez pas besoin d'envelopper cela dans $ .when (< / code> ou quoi que ce soit, cela compliquera inutilement les choses; le code de la réponse ci-dessus devrait fonctionner tel quel
Génial merci. Je retrousse mes manches maintenant
Si votre surnom "Performance" est lié au sport automobile, vous allez adorer mon site. BTW, Puisque nous utilisons AJAX et que j'ai lu que getScript ne met pas en cache, y a-t-il une simple ligne que nous pourrions ajouter ici afin de permettre à la machine d'un utilisateur de mettre en cache ces scripts pendant un autre jour pendant qu'ils y sont?
Ajouter un mécanisme de mise en cache serait beaucoup plus compliqué. Vous pouvez stocker chaque résultat de script dans localStorage ou quelque chose comme ça, puis vérifier localStorage avant d'appeler getScript . Ajoutez un numéro de version qui est modifié chaque fois que vous modifiez le script afin que les utilisateurs téléchargent la version la plus récente au lieu de charger l'ancienne à partir de leur système local.
Si je suis sûr que ces scripts sont déjà sains et fonctionnent bien, y a-t-il un mal à supprimer le .catch (... et pourquoi le () avant catch? Je sais juste assez pour être dangereux et j'apprends toujours mais je suis presque sûr de ce que vous partagé ici est la dernière et la meilleure syntaxe pour accomplir cela.
Merci Certain Performance. Vous l'avez résolu !! Maintenant jusqu'à 98 sur Google Page Speed Insights
Le () avant le catch est nécessaire pour appeler la fonction async . Sans cela, il s'agit simplement d'une expression de fonction inutilisée, mais vous voulez l'invoquer pour que son code s'exécute. Le .catch est nécessaire pour une bonne interface utilisateur - il existe de nombreux facteurs indépendants de votre volonté qui peuvent interrompre la connexion entre le client et votre serveur, et mettre un .catch sur celui-ci vous permet d'observer et de gérer ce genre d'erreurs plus gracieusement que l'échec silencieux.
m obtenir une erreur de syntaxe à partir de cela dans les navigateurs plus anciens, apparemment due à async / await. Toutes les idées sont les bienvenues
Chaque fois que vous utilisez des fonctionnalités de langage plus récentes (que le code professionnel devrait utiliser pour une bonne lisibilité), pour rendre les scripts compatibles avec les navigateurs obsolètes, la solution la plus fiable consiste à utiliser Babel pour transpiler la syntaxe automatiquement. Si vous souhaitez cibler IE, vous voulez une sortie dans la syntaxe ES5.
Sry pour prolonger la discussion dans les commentaires, mais j'espère que cela sera également bénéfique pour les autres: je ne veux pas utiliser babel principalement en raison du chargement des dépendances adtl (note latérale, mon site fonctionne parfaitement sans "Bootstrap", "Font Awesome "ou des conneries similaires et je ne veux pas commencer par utiliser Babel.) Il doit y avoir un moyen d'accomplir l'idée originale pour les navigateurs plus anciens et plus récents, avec un peu de chance dans JS natif et certainement sans aucune dépendance addtl et sans ballonnement et polyfills comme on peut le voir ici: stackoverflow.com/questions/47684102/…
Babel est une dépendance de développement , pas une dépendance de production , heureusement - cela n'aura aucun effet négatif sur les utilisateurs, autre que de laisser les navigateurs obsolètes exécuter votre code. Je considérerais Babel comme essentiel pour tout projet raisonnablement professionnel; il garde le code source court, propre et lisible, lorsque vous pouvez coder dans la dernière et la meilleure version du langage.
Si vous ne pouvez utiliser aucune fonctionnalité de langage moderne et que vous ne pouvez utiliser qu'ES5, vous pouvez demander à chaque getScript de s'appeler récursivement avec le chemin suivant, mais c'est beaucoup plus laid (et les objets de type jQuery Promise ont un certain nombre de problèmes)
Merci pour votre aide Certain. J'ai essayé votre exemple précédent via Babel mais j'ai remarqué que cela donne toujours une erreur de syntaxe sur iOS 9 ou Win XP, je dois les laisser derrière moi et continuer
En js pur
['/1.js', '/2.js', '/3.js', '/4.js', '/5.js'].forEach(function(script) {
var scriptElement = document.createElement("script");
scriptElement.src = script;
// append script element where you want (head or body)
document.head.appendChild(scriptElement);
});
Pour tous ceux qui utilisent jQuery, j'ai amélioré le script @adeneo afin qu'il charge tous les scripts dans l'ordre spécifié. Il ne fait pas de chargement en chaîne, donc c'est très rapide, mais si vous voulez encore plus rapide, modifiez le temps d'attente de 50 ms.
var script_arr = [
'myscript1.js',
'myscript2.js',
'myscript3.js'
];
$.getMultiScripts(script_arr, '/mypath/').done(function() {
// all scripts loaded
});
Comment utiliser:
$.getMultiScripts = function(arr, path) {
function executeInOrder(scr, code, resolve) {
// if its the first script that should be executed
if (scr == arr[0]) {
arr.shift();
eval(code);
resolve();
console.log('executed', scr);
} else {
// waiting
setTimeout(function(){
executeInOrder(scr, code, resolve);
}, 50);
}
}
var _arr = $.map(arr, function(scr) {
return new Promise((resolve) => {
jQuery.ajax({
type: "GET",
url: (path || '') + scr,
dataType: "text",
success: function(code) {
console.log('loaded ', scr);
executeInOrder(scr, code, resolve);
},
cache: true
});
});
});
_arr.push($.Deferred(function( deferred ){
$( deferred.resolve );
}));
return $.when.apply($, _arr);
}
À moins que vous ne puissiez inclure les scripts dans le HTML, ce qui ne semble pas être le cas, vous devrez utiliser Ajax ou une requête réseau pour les récupérer, non?
@CertainPerformance Je suis trouble sur le besoin d'AJAX, mais si c'est nécessaire, même pour les scripts internes, cela éclaire la question pour moi, mais je ne sais toujours pas comment les charger de manière synchrone et je serais heureux de recevoir des conseils. Je lis toujours ailleurs malgré tout. Merci
S'ils doivent être effectués dans l'ordre, vous devrez enchaîner les appels d'appels
$ .getScriptdans le rappel de chacun des précédents. Utilisez-vous l'architecture SPA pour le site? Je demande en essayant de déterminer la raison du chargement asynchrone des scripts; c'est généralement beaucoup plus compliqué que cela ne vaut la peine.@RoryMcCrossan Je suis désolé, IDK ce qu'est l'architecture SPA. Probablement pas. Juste une poignée de scripts qui dépendent de chaque script précédent. Cela fonctionne à merveille en les incluant dans HTML, le site n'en a tout simplement pas besoin jusqu'à ce qu'un utilisateur clique sur un bouton
Ah ok, donc si cela est fait pour l'optimisation, ce n'est pas tout à fait la bonne approche. Je suggérerais plutôt d'utiliser le regroupement et la minification de votre JS (et CSS). De cette façon, tous les scripts sont chargés une fois et mis en cache. Toutes les demandes de page ultérieures n'auront alors aucun temps de chargement pour le JS / CSS car elles sont mises en cache. Cela évite également la complexité des requêtes AJAX que vous devez effectuer, ainsi que les bégaiements de chargement que vous obtiendrez.
Bons points, merci. Je ne veux tout simplement pas charger ces scripts jusqu'à ce que l'interaction de l'utilisateur en ait besoin