pattern nodejs implement es6 javascript node.js design-patterns singleton

javascript - implement - Patrón Singleton en nodejs-¿es necesario?



singleton javascript es6 (9)

Esto tiene que ver básicamente con el almacenamiento en memoria caché de nodejs. Simple y simple.

https://nodejs.org/api/modules.html#modules_caching

(v 6.3.1)

Almacenamiento en caché

Los módulos se almacenan en caché después de la primera vez que se cargan. Esto significa (entre otras cosas) que cada llamada a requerir (''foo'') obtendrá exactamente el mismo objeto devuelto, si se resolvería en el mismo archivo.

Múltiples llamadas a requerir (''foo'') pueden no causar que el código del módulo se ejecute varias veces. Esta es una característica importante. Con él, se pueden devolver objetos "parcialmente hechos", permitiendo así que las dependencias transitivas se carguen incluso cuando causarían ciclos.

Si desea que un módulo ejecute código varias veces, exporte una función y llame a esa función.

Módulo Caching Advertats

Los módulos se almacenan en caché en función de su nombre de archivo resuelto. Dado que los módulos pueden resolverse con un nombre de archivo diferente según la ubicación del módulo que realiza la llamada (cargar desde carpetas node_modules), no es una garantía que requiera (''foo'') devolverá siempre el mismo objeto exacto, si se resuelve en diferentes archivos .

Además, en sistemas de archivos o sistemas operativos que no distinguen entre mayúsculas y minúsculas, los diferentes nombres de archivos resueltos pueden apuntar al mismo archivo, pero la memoria caché los tratará como diferentes módulos y volverá a cargar el archivo varias veces. Por ejemplo, require (''./ foo'') y require (''./ FOO'') devuelve dos objetos diferentes, independientemente de si ./foo y ./FOO son o no el mismo archivo.

Entonces 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).

Hace poco encontré este artículo sobre cómo escribir un singleton en Node.js. Sé que la documentación de require states que:

Los módulos se almacenan en caché después de la primera vez que se cargan. Múltiples llamadas a requerir (''foo'') pueden no causar que el código del módulo se ejecute varias veces.

Por lo tanto, parece que cada módulo requerido se puede usar fácilmente como singleton sin el código repetitivo de singleton.

Pregunta:

¿El artículo anterior proporciona una ronda sobre la solución para crear un singleton?


Los singletons 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 rellenar la referencia en una variable global.

Simplemente escriba un módulo que cree la var global si no existe, luego devuelve una referencia a eso.

@ allen-luce tenía razón con su ejemplo de código de pie de página copiado aquí:

singleton.getInstance = function(){ if(global.singleton_instance === undefined) global.singleton_instance = new singleton(); return global.singleton_instance; }; module.exports = singleton.getInstance();

pero es importante tener en cuenta que no se requiere el uso de la new palabra clave. Cualquier objeto viejo, función, iife, etc. funcionará, no hay vudú OOP pasando aquí.

puntos de bonificación si cierra un 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.


Manteniéndolo simple.

foo.js

function foo() { bar: { doSomething: function(arg, callback) { return callback(''Echo '' + arg); }; } return bar; }; module.exports = foo();

Entonces solo

var foo = require(__dirname + ''foo''); foo.doSomething(''Hello'', function(result){ console.log(result); });


Mirando un poco más allá en el Módulo caching advertencias en los documentos de los módulos:

Los módulos se almacenan en caché en función de su nombre de archivo resuelto. Dado que los módulos pueden resolverse con un nombre de archivo diferente según la ubicación del módulo que realiza la llamada (cargar desde carpetas node_modules), no es una garantía que requiera (''foo'') devolverá siempre el mismo objeto exacto, si se resuelve en diferentes archivos .

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 son . Al igual que @mkoryak, no puedo encontrar un caso en el que un solo archivo pueda resolverse con diferentes nombres de archivo (sin usar enlaces simbólicos). Pero (como los comentarios de @JohnnyHK), cada una de las copias de un archivo en diferentes directorios node_modules se cargará y almacenará por separado.


No necesita nada especial para hacer un singleton en js, el código en el artículo podría ser:

var socketList = {}; module.exports = { add: function() { }, ... };

Fuera de node.js (por ejemplo, en el navegador js), necesita agregar la función de contenedor manualmente (se realiza automáticamente en node.js):

var singleton = function() { var socketList = {}; return { add: function() {}, ... }; }();


Todo lo anterior es muy complicado. Hay una escuela de pensamiento que dice que los patrones de diseño muestran deficiencias en el lenguaje real.

Los lenguajes con OOP basado en prototipos (sin clase) no necesitan un patrón singleton en absoluto. Simplemente creas un objeto (tonelada) sobre la marcha y luego lo usas.

En cuanto a los módulos en el nodo, sí, de forma predeterminada se almacenan en caché, pero se puede ajustar, por ejemplo, si desea cargar en caliente los cambios del módulo.

Pero sí, si desea utilizar el objeto compartido en todas partes, ponerlo en un módulo de exportación está bien. Simplemente no lo complique con "patrón único", no es necesario en JavaScript.


Un singleton en node.js (o en el navegador JS, para el caso) así es completamente innecesario.

Como los módulos están en caché y con estado, el ejemplo proporcionado en el enlace que proporcionó podría reescribirse fácilmente de forma mucho más simple:

var socketList = {}; exports.add = function (userId, socket) { if (!socketList[userId]) { socketList[userId] = socket; } }; exports.remove = function (userId) { delete socketList[userId]; }; exports.getSocketList = function () { return socketList; }; // or // exports.socketList = socketList


La única respuesta aquí que usa clases de ES6

// SummaryModule.js class Summary { init(summary) { this.summary = summary } anotherMethod() { // do something } } module.exports = new Summary()

requiere este singleton con:

const summary = require(''./SummaryModule'') summary.init(true) summary.anotherMethod()

El único problema aquí es que no se pueden pasar los parámetros al constructor de la clase, pero eso se puede eludir llamando manualmente a un método init .


No. Cuando el caché de módulos de Node falla, ese patrón singleton falla. Modifiqué el ejemplo para ejecutar de manera significativa en OSX:

var sg = require("./singleton.js"); var sg2 = require("./singleton.js"); sg.add(1, "test"); sg2.add(2, "test2"); console.log(sg.getSocketList(), sg2.getSocketList());

Esto da la salida que el autor anticipó:

{ ''1'': ''test'', ''2'': ''test2'' } { ''1'': ''test'', ''2'': ''test2'' }

Pero una pequeña modificación frustra el almacenamiento en caché. En OSX, haz esto:

var sg = require("./singleton.js"); var sg2 = require("./SINGLETON.js"); sg.add(1, "test"); sg2.add(2, "test2"); console.log(sg.getSocketList(), sg2.getSocketList());

O, en Linux:

% ln singleton.js singleton2.js

A continuación, cambie la línea de sg2 a:

var sg2 = require("./singleton2.js");

Y bam , el singleton es derrotado:

{ ''1'': ''test'' } { ''2'': ''test2'' }

No sé de una manera aceptable de evitar esto. Si realmente sientes la necesidad de hacer algo como singleton y estás de acuerdo en contaminar el espacio de nombres global (y los muchos problemas que pueden surgir), puedes cambiar la getInstance() del autor y exports líneas a:

singleton.getInstance = function(){ if(global.singleton_instance === undefined) global.singleton_instance = new singleton(); return global.singleton_instance; } module.exports = singleton.getInstance();

Dicho esto, nunca me he encontrado con una situación en un sistema de producción en la que tuviera que hacer algo como esto. También nunca sentí la necesidad de usar el patrón singleton en Javascript.