Saltar al contenido

Patrón singleton en nodejs: ¿es necesario?

Solución:

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 clases) 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 “patrón singleton”, no es necesario en JavaScript.

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

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 require (‘foo’) obtendrá exactamente el mismo objeto devuelto, si se resuelve en el mismo archivo.

Es posible que varias llamadas a require (‘foo’) no hagan 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 se carguen las dependencias transitivas 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.

Advertencias sobre el almacenamiento en caché del módulo

Los módulos se almacenan en caché según su nombre de archivo resuelto. Dado que los módulos pueden resolverse en un nombre de archivo diferente según la ubicación del módulo de llamada (cargando desde carpetas de node_modules), no es una garantía de que require (‘foo’) siempre devolverá exactamente el mismo objeto, si se resolviera en archivos diferentes .

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

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

Para ser MUY claro, si hace esto 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 propia forma de Node.js para importar / exportar módulos). Es muy probable que Node.js cambie a 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

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:

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 el resultado que el autor anticipó:

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

Pero una pequeña modificación derrota al 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

Entonces cambia el sg2 requiere línea para:

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

Y bam, el singleton es derrotado:

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

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 el nombre del autor. getInstance() 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. Tampoco he sentido nunca la necesidad de usar el patrón singleton en Javascript.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *