Quelle est la différence entre Require.js et la simple création d'un élément <script> dans le DOM? [fermé]

138

Quelle est la différence entre utiliser Require.JS et créer simplement un <script>élément dans le DOM?

Ma compréhension de Require.JS est qu'il offre la possibilité de charger des dépendances, mais cela ne peut-il pas simplement être fait en créant un <script>élément qui charge le fichier JS externe nécessaire?

Par exemple, supposons que j'ai la fonction doStuff(), qui nécessite la fonction needMe(). doStuff()se trouve dans le fichier externe do_stuff.js, tandis que needMe()dans le fichier externe need_me.js.

En procédant de la manière Require.JS:

define(['need_me'],function(){
    function doStuff(){
        //do some stuff
        needMe();
        //do some more stuff
    }
});

Pour ce faire, créez simplement un élément de script:

function doStuff(){
    var scriptElement  = document.createElement('script');
    scriptElement.src = 'need_me.js';
    scriptElement.type = 'text/javascript';
    document.getElementsByTagName('head')[0].appendChild(scriptElement);

    //do some stuff
    needMe();
    //do some more stuff
}

Les deux fonctionnent. Cependant, la deuxième version ne m'oblige pas à charger toute la bibliothèque Require.js. Je ne vois pas vraiment de différence fonctionnelle ...

maxedison
la source
1
qu'en est-il de la mise en cache du navigateur, est-ce que requirejs l'interfère?
Muhammad Umer
Je rouvre cela parce qu'il demande la différence entre deux choses très similaires. On peut y répondre objectivement, et je ne vois pas où l'opinion s'y rattache.
RamenChef

Réponses:

43

Voici le bel article sur ajaxian.com expliquant pourquoi l'utiliser:

RequireJS: chargement JavaScript asynchrone

  • une sorte de # inclure / importer / exiger
  • possibilité de charger des dépendances imbriquées
  • facilité d'utilisation pour le développeur mais soutenue par un outil d'optimisation qui facilite le déploiement
Sarfraz
la source
2
J'avais lu ceux-ci, mais maintenant que j'y pense plus, je me rends compte que l'idée de dépendances imbriquées ne peut pas être réalisée en écrivant simplement des balises <script>. Merci.
maxedison
37
"la facilité d'utilisation pour le développeur" ne pouvait pas être plus éloignée de la vérité. Il a certainement une courbe d'apprentissage abrupte pour vous et toute autre personne qui viendra travailler dans ce projet.
Sahat Yalkabov
3
@TwilightPony Je ne me considère pas si brillant et requirejs n'était pas vraiment une chose difficile à obtenir. Cela vous évite d'avoir à vous soucier des dépendances et accélère la page. Votre code devient plus en ligne avec la programmation côté serveur dans la façon dont vous déclarez vos dépendances, ce que je trouve personnellement rafraîchissant et simple. La syntaxe était minimale et fermée par la conception, puis définit la feuille de route pour la production afin de combiner facilement vos scripts. En plus de ce débogage, il y a tout comme les déclarations statiques. Je ne sais pas ce qui est plus facile que ça. Beaucoup plus difficile dans l'autre sens que je l'ai fait dans l'autre sens.
Jason Sebring
Je me bats. Surtout avec des modules qui tentent de s'attacher à des objets globaux. (Modules React) ...
Geilt
1
Les commentaires sur cette page m'ont en fait laissé le sentiment qu'il fallait fuir et non pas exiger. Surtout celui près du bas qui renvoie
Dave Kanter
52

Quels avantages Require.JS offre-t-il par rapport à la simple création d'un élément dans le DOM?

Dans votre exemple, vous créez la balise de script de manière asynchrone, ce qui signifie que votre needMe()fonction sera appelée avant que le fichier need_me.js ne termine le chargement. Cela entraîne des exceptions non interceptées où votre fonction n'est pas définie.

Au lieu de cela, pour que ce que vous suggérez fonctionne réellement, vous devez faire quelque chose comme ceci:

function doStuff(){
    var scriptElement  = document.createElement('script');
    scriptElement.src = 'need_me.js';
    scriptElement.type = 'text/javascript';

    scriptElement.addEventListener("load", 
        function() { 
            console.log("script loaded - now it's safe to use it!");

            // do some stuff
            needMe();
            //do some more stuff

        }, false);

    document.getElementsByTagName('head')[0].appendChild(scriptElement);

}

On peut soutenir qu'il peut être préférable ou non d'utiliser un gestionnaire de packages tel que RequireJS ou d'utiliser une stratégie purement JavaScript comme démontré ci-dessus. Bien que votre application Web puisse se charger plus rapidement, l'appel des fonctionnalités et des fonctionnalités sur le site serait plus lent car cela impliquerait d'attendre le chargement des ressources avant que cette action puisse être effectuée.

Si une application Web est conçue en tant qu'application d'une seule page, sachez que les utilisateurs ne rechargeront pas la page très souvent. Dans ces cas, tout précharger aiderait à rendre l'expérience plus rapide alors qu'en réalité utilisez l'application. Dans ces cas, vous avez raison, on peut simplement charger toutes les ressources simplement en incluant les balises de script dans l'en-tête ou le corps de la page.

Cependant, si vous créez un site Web ou une application Web qui suit le modèle plus traditionnel où l'on passe d'une page à l'autre, provoquant le rechargement des ressources, une approche de chargement différé peut aider à accélérer ces transitions.

jmort253
la source
10

Quelques autres raisons très pointues pour lesquelles l'utilisation de RequireJS a du sens:

  1. La gestion de vos propres dépendances s'effondre rapidement pour des projets de taille.
  2. Vous pouvez avoir autant de petits fichiers que vous le souhaitez et vous n'avez pas à vous soucier du suivi des dépendances ou de l'ordre de chargement.
  3. RequireJS permet d'écrire une application modulaire entière sans toucher à l'objet de la fenêtre.

Tiré des commentaires de rmurphey ici dans ce Gist .

Les couches d'abstraction peuvent être un cauchemar à apprendre et à s'adapter, mais quand cela sert un objectif et le fait bien, cela a du sens.

girls_can_code_too
la source
9
Vous devez toujours gérer tous ceux qui nécessitent et définir les instructions, les fichiers de configuration, les collisions avec d'autres systèmes et bibliothèques qui n'ont pas implémenté la spécification AMD, etc. J'ai essayé d'utiliser Require.JS dans un projet node-webkit et Require.JS m'a combattu à chaque étape du processus ... Comparez cela avec le simple fait de commander des scripts d'une certaine manière ... Bien sûr, vous gagnez en chargement paresseux avec Require.JS, c'est pourquoi j'ai essayé de le faire fonctionner. :)
jmort253
Je suis totalement d'accord avec @ jmort253, c'était une lutte au début, mais maintenant je l'aime beaucoup. Les trois points sont corrects! Et AMDifier une bibliothèque ne devrait pas être si difficile ... ou utiliser la cale.
Legends
0

Voici un exemple plus concret.

Je travaille dans un projet avec 60 fichiers. Nous avons 2 modes de fonctionnement différents.

  1. Chargez une version concaténée, 1 gros fichier. (Production)

  2. Charger les 60 fichiers (développement)

Nous utilisons un chargeur, nous n'avons donc qu'un seul script dans la page Web

<script src="loader.js"></script>

Par défaut, le mode n ° 1 (chargement du seul gros fichier concaténé). Pour exécuter le mode # 2 (fichiers séparés), nous définissons un indicateur. Ça pourrait être n'importe quoi. Une clé dans la chaîne de requête. Dans cet exemple, nous faisons simplement ceci

<script>useDebugVersion = true;</script>
<script src="loader.js"></script>

loader.js ressemble à quelque chose comme ça

if (useDebugVersion) {
   injectScript("app.js");
   injectScript("somelib.js");
   injectScript("someotherlib.js");
   injectScript("anotherlib.js");
   ... repeat for 60 files ...
} else {
   injectScript("large-concatinated.js");
}

Le script de construction est juste un fichier .sh qui ressemble à ceci

cat > large-concantinated.js app.js somelib.js someotherlib.js anotherlib.js

etc...

Si un nouveau fichier est ajouté, nous utiliserons probablement le mode # 2 puisque nous faisons du développement, nous devons ajouter une injectScript("somenewfile.js")ligne à loader.js

Ensuite, pour la production, nous devons également ajouter somenewfile.js à notre script de construction. Une étape que nous oublions souvent et que nous recevons ensuite des messages d'erreur.

En passant à AMD, nous n'avons pas à modifier 2 fichiers. Le problème de la synchronisation de loader.js et du script de construction disparaît. En utilisant r.jsou webpackil peut simplement lire le code pour construirelarge-concantinated.js

Il peut également gérer les dépendances, par exemple nous avons eu 2 fichiers lib1.js et lib2.js chargés comme ceci

injectScript("lib1.js");
injectScript("lib2.js");

lib2 a besoin de lib1. Il contient du code qui fait quelque chose comme

lib1Api.installPlugin(...);

Mais comme les scripts injectés sont chargés de manière asynchrone, il n'y a aucune garantie qu'ils se chargeront dans le bon ordre. Ces 2 scripts ne sont pas des scripts AMD mais en utilisant require.js nous pouvons lui dire leurs dépendances

require.config({
    paths: {
        lib1: './path/to/lib1',
        lib2: './path/to/lib2',
    },
    shim: {
        lib1: {
            "exports": 'lib1Api',
        },
        lib2: {
            "deps": ["lib1"],
        },
    }
});

I notre module qui utilise lib1 nous faisons ceci

define(['lib1'], function(lib1Api) {
   lib1Api.doSomething(...);
});

Maintenant, require.js va injecter les scripts pour nous et il n'injectera pas lib2 tant que lib1 n'aura pas été chargé puisque nous lui avons dit que lib2 dépend de lib1. Il ne démarrera pas non plus notre module qui utilise lib1 tant que lib2 et lib1 ne seront pas chargés.

Cela rend le développement agréable (pas d'étape de construction, pas de souci pour l'ordre de chargement) et cela rend la production agréable (pas besoin de mettre à jour un script de construction pour chaque script ajouté).

En prime, nous pouvons utiliser le plugin babel de webpack pour exécuter babel sur le code des anciens navigateurs et encore une fois, nous n'avons pas non plus à maintenir ce script de construction.

Notez que si Chrome (notre navigateur de choix) a commencé à prendre en charge import pour de vrai, nous passerions probablement à cela pour le développement, mais cela ne changerait vraiment rien. Nous pourrions toujours utiliser webpack pour créer un fichier concaténé et nous pourrions l'utiliser pour exécuter babel sur le code pour tous les navigateurs.

Tout cela est gagné en n'utilisant pas de balises de script et en utilisant AMD

gman
la source