Recientemente encontré este artículo sobre cómo escribir un singleton en Node.js. Conozco la documentación de require
estados que:
Los módulos se almacenan en caché después de la primera vez que se cargan. Es posible que varias llamadas a
require('foo')
no hagan que el código del módulo se ejecute varias veces.
Por lo tanto, parece que todos los módulos necesarios se pueden usar fácilmente como singleton sin el código repetitivo singleton.
Pregunta:
¿El artículo anterior proporciona una solución completa para crear un singleton?
javascript
node.js
design-patterns
singleton
mkoryak
fuente
fuente
Respuestas:
Esto tiene básicamente que ver con el almacenamiento en caché de nodejs. Simple y llanamente.
https://nodejs.org/api/modules.html#modules_caching
(v 6.3.1)
Así que en términos simples.
Si quieres un Singleton; exportar un objeto .
Si no quieres un Singleton; exportar una función (y hacer cosas / devolver cosas / lo que sea en esa función).
Para ser MUY claro, si lo hace correctamente, debería funcionar, consulte https://stackoverflow.com/a/33746703/1137669 (la respuesta de Allen Luce). Explica en código lo que sucede cuando el almacenamiento en caché falla debido a nombres de archivo resueltos de manera diferente. Pero si SIEMPRE resuelve con el mismo nombre de archivo, debería funcionar.
Actualización 2016
creando un verdadero singleton en node.js con símbolos es6 Otra solución : en este enlace
Actualización 2020
Esta respuesta se refiere a CommonJS (la forma propia de Node.js para importar / exportar módulos). Es muy probable que Node.js cambie a los módulos ECMAScript : https://nodejs.org/api/esm.html (ECMAScript es el nombre real de JavaScript si no lo sabía)
Al migrar a ECMAScript, lea lo siguiente por ahora: https://nodejs.org/api/esm.html#esm_writing_dual_packages_ while_avoiding_or_minimizing_hazards
fuente
Todo lo anterior es demasiado complicado. Hay una escuela de pensamiento que dice que los patrones de diseño muestran deficiencias del lenguaje real.
Los lenguajes con POO basada en prototipos (sin clase) no necesitan un patrón singleton en absoluto. Simplemente crea un objeto único (tonelada) sobre la marcha y luego lo usa.
En cuanto a los módulos en el nodo, sí, de forma predeterminada se almacenan en caché, pero se puede modificar, por ejemplo, si desea cargar en caliente los cambios del módulo.
Pero sí, si desea utilizar un objeto compartido en todas partes, ponerlo en un módulo de exportación está bien. Simplemente no lo complique con el "patrón singleton", no es necesario en JavaScript.
fuente
There is a school of thought which says design patterns are showing deficiencies of actual language.
No. Cuando falla el almacenamiento en caché del módulo de Node, ese patrón singleton falla. Modifiqué el ejemplo para que se ejecute de manera significativa en OSX:
Esto da el resultado que el autor anticipó:
Pero una pequeña modificación derrota al almacenamiento en caché. En OSX, haz esto:
O, en Linux:
Luego cambie la
sg2
línea requerida a:Y bam , el singleton es derrotado:
No conozco una forma aceptable de solucionar esto. Si realmente siente la necesidad de hacer algo parecido a un singleton y está de acuerdo con contaminar el espacio de nombres global (y los muchos problemas que pueden resultar), puede cambiar las líneas
getInstance()
y del autorexports
a:Dicho esto, nunca me he encontrado con una situación en un sistema de producción en la que necesite hacer algo como esto. Tampoco he sentido nunca la necesidad de utilizar el patrón singleton en Javascript.
fuente
Mirando un poco más en las advertencias de almacenamiento en caché del módulo en los documentos de los módulos:
Entonces, dependiendo de dónde se encuentre cuando necesite un módulo, es posible obtener una instancia diferente del módulo.
Parece que los módulos no son una solución simple para crear singletons.
Editar: O tal vez lo sean . Como @mkoryak, no puedo pensar en un caso en el que un solo archivo pueda resolverse en diferentes nombres de archivo (sin usar enlaces simbólicos). Pero (como comenta @JohnnyHK), se
node_modules
cargarán y almacenarán por separado varias copias de un archivo en diferentes directorios.fuente
node_modules
donde cada uno depende del mismo módulo, pero hay copias separadas de ese módulo dependiente bajo elnode_modules
subdirectorio de cada uno de los dos módulos diferentes.require('./db')
encuentra en dos archivos separados, el código deldb
módulo se ejecuta dos vecesrequire('../lib/myModule.js');
en un archivo yrequire('../lib/mymodule.js');
en otro y no entregó el mismo objeto.Un singleton en node.js (o en el navegador JS, para el caso) como ese es completamente innecesario.
Dado que los módulos se almacenan en caché y tienen estado, el ejemplo que se proporciona en el enlace que proporcionó podría reescribirse fácilmente de manera mucho más simple:
fuente
may not
aplica cuandonpm link
otros módulos durante el desarrollo. Por lo tanto, tenga cuidado al usar módulos que se basan en una sola instancia, como eventBus.La única respuesta aquí que usa clases ES6
requieren este singleton con:
El único problema aquí es que no puede pasar parámetros al constructor de la clase, pero eso puede evitarse llamando manualmente a un
init
método.fuente
summary
en otra clase, sin inicializarla nuevamente?No necesita nada especial para hacer un singleton en js, el código del artículo también podría ser:
Fuera de node.js (por ejemplo, en el navegador js), debe agregar la función de contenedor manualmente (se hace automáticamente en node.js):
fuente
Los singleton están bien en JS, simplemente no necesitan ser tan detallados.
En el nodo, si necesita un singleton, por ejemplo, para usar la misma instancia de ORM / DB en varios archivos en su capa de servidor, puede incluir la referencia en una variable global.
Simplemente escriba un módulo que cree la var global si no existe, luego devuelva una referencia a eso.
@ allen-luce lo hizo bien con su ejemplo de código de nota al pie copiado aquí:
pero es importante tener en cuenta que no
new
es necesario utilizar la palabra clave . Cualquier objeto antiguo, función, vida, etc. funcionará; aquí no hay vudú OOP.puntos de bonificación si cierra algún obj dentro de una función que devuelve una referencia a él, y hace que esa función sea global, incluso la reasignación de la variable global no afectará las instancias ya creadas a partir de ella, aunque esto es cuestionablemente útil.
fuente
module.exports = new Foo()
porque module.exports no se ejecutará nuevamente, a menos que haga algo realmente estúpidoManteniéndolo simple.
foo.js
Entonces solo
fuente