Je suis récemment tombé sur cet article sur la façon d'écrire un singleton dans Node.js. Je connais la documentation des require
états que:
Les modules sont mis en cache après leur premier chargement. Plusieurs appels à
require('foo')
peuvent ne pas entraîner l'exécution du code du module plusieurs fois.
Il semble donc que chaque module requis puisse être facilement utilisé comme un singleton sans le code standard du singleton.
Question:
L'article ci-dessus fournit-il une solution complète pour créer un singleton?
Réponses:
Cela a essentiellement à voir avec la mise en cache de nodejs. Clair et simple.
https://nodejs.org/api/modules.html#modules_caching
(v 6.3.1)
Donc en termes simples.
Si vous voulez un Singleton; exporter un objet .
Si vous ne voulez pas de Singleton; exporter une fonction (et faire des trucs / renvoyer des trucs / quoi que ce soit dans cette fonction).
Pour être TRÈS clair, si vous faites cela correctement, cela devrait fonctionner, regardez https://stackoverflow.com/a/33746703/1137669 (réponse d'Allen Luce). Il explique dans le code ce qui se passe lorsque la mise en cache échoue en raison de noms de fichiers résolus différemment. Mais si vous résolvez TOUJOURS le même nom de fichier, cela devrait fonctionner.
Mise à jour 2016
création d'un vrai singleton dans node.js avec des symboles es6 Une autre solution : dans ce lien
Mise à jour 2020
Cette réponse se réfère à CommonJS (la méthode propre à Node.js pour importer / exporter des modules). Node.js basculera probablement vers les modules ECMAScript : https://nodejs.org/api/esm.html (ECMAScript est le vrai nom de JavaScript si vous ne le saviez pas)
Lors de la migration vers ECMAScript, lisez ce qui suit pour le moment: https://nodejs.org/api/esm.html#esm_writing_dual_packages_ While_avoiding_or_minimizing_hazards
la source
Tout ce qui précède est trop compliqué. Il y a une école de pensée qui dit que les modèles de conception montrent des lacunes du langage réel.
Les langages avec une POO basée sur un prototype (sans classe) n'ont pas du tout besoin d'un modèle de singleton. Vous créez simplement un seul objet (tonne) à la volée, puis vous l'utilisez.
En ce qui concerne les modules dans node, oui, par défaut, ils sont mis en cache, mais cela peut être modifié par exemple si vous voulez un chargement à chaud des modifications de modules.
Mais oui, si vous souhaitez utiliser un objet partagé partout, le mettre dans un module d'export est très bien. Il suffit de ne pas le compliquer avec un "motif singleton", pas besoin de cela en JavaScript.
la source
There is a school of thought which says design patterns are showing deficiencies of actual language.
Non. Lorsque la mise en cache du module de Node échoue, ce modèle de singleton échoue. J'ai modifié l'exemple pour fonctionner de manière significative sur OSX:
Cela donne le résultat attendu par l'auteur:
Mais une petite modification empêche la mise en cache. Sous OSX, procédez comme suit:
Ou, sous Linux:
Puis changez la
sg2
ligne requise en:Et bam , le singleton est vaincu:
Je ne connais pas de moyen acceptable de contourner cela. Si vous vous sentez vraiment la nécessité de faire quelque chose comme singleton et sont d' accord avec la pollution de l'espace de nommage global (et les nombreux problèmes qui peuvent en résulter), vous pouvez changer de l'auteur
getInstance()
etexports
lignes en:Cela dit, je n'ai jamais rencontré de situation sur un système de production où je devais faire quelque chose comme ça. Je n'ai jamais ressenti le besoin d'utiliser le modèle singleton en Javascript.
la source
En regardant un peu plus loin les avertissements de mise en cache des modules dans la documentation des modules:
Ainsi, selon l'endroit où vous vous trouvez lorsque vous avez besoin d'un module, il est possible d'obtenir une instance différente du module.
On dirait que les modules ne sont pas une solution simple pour créer des singletons.
Edit: Ou peut-être qu'ils le sont . Comme @mkoryak, je ne peux pas proposer de cas où un seul fichier pourrait se résoudre en différents noms de fichiers (sans utiliser de liens symboliques). Mais (comme le commente @JohnnyHK), plusieurs copies d'un fichier dans différents
node_modules
répertoires seront chacune chargées et stockées séparément.la source
node_modules
dont chacun dépend du même module, mais il y a des copies séparées de ce module dépendant dans le sous-node_modules
répertoire de chacun des deux modules différents.require('./db')
est dans deux fichiers séparés, le code dudb
module s'exécute deux foisrequire('../lib/myModule.js');
dans un fichier etrequire('../lib/mymodule.js');
dans un autre et il n'a pas livré le même objet.Un singleton dans node.js (ou dans le navigateur JS, d'ailleurs) comme ça est complètement inutile.
Puisque les modules sont mis en cache et avec état, l'exemple donné sur le lien que vous avez fourni pourrait facilement être réécrit beaucoup plus simplement:
la source
may not
s'applique lorsque vous avez d'npm link
autres modules pendant le développement. Soyez donc prudent lorsque vous utilisez des modules qui reposent sur une seule instance telle qu'un eventBus.La seule réponse ici qui utilise les classes ES6
nécessitent ce singleton avec:
Le seul problème ici est que vous ne pouvez pas passer de paramètres au constructeur de classe, mais cela peut être contourné en appelant manuellement une
init
méthode.la source
summary
dans une autre classe, sans la réinitialiser?Vous n'avez besoin de rien de spécial pour faire un singleton en js, le code de l'article pourrait tout aussi bien être:
En dehors de node.js (par exemple, dans le navigateur js), vous devez ajouter la fonction wrapper manuellement (cela se fait automatiquement dans node.js):
la source
Les singletons sont bien dans JS, ils n'ont tout simplement pas besoin d'être aussi verbeux.
Dans node si vous avez besoin d'un singleton, par exemple pour utiliser la même instance ORM / DB dans divers fichiers de votre couche serveur, vous pouvez insérer la référence dans une variable globale.
Écrivez simplement un module qui crée la variable globale si elle n'existe pas, puis renvoie une référence à cela.
@ allen-luce avait raison avec son exemple de code de note de bas de page copié ici:
mais il est important de noter que l'utilisation du
new
mot-clé n'est pas obligatoire. Tout ancien objet, fonction, iife, etc. fonctionnera - il n'y a pas de vaudou POO qui se passe ici.des points bonus si vous fermez un objet dans une fonction qui lui renvoie une référence, et que vous en faites une fonction globale - alors même la réaffectation de la variable globale ne supprimera pas les instances déjà créées à partir de celle-ci - bien que cela soit très utile.
la source
module.exports = new Foo()
parce que module.exports ne s'exécutera pas à nouveau, à moins que vous ne fassiez quelque chose de vraiment stupideRester simple.
toto.js
Alors juste
la source