Recentemente encontrei este artigo sobre como escrever um singleton em Node.js. Conheço a documentação dos require
estados que:
Os módulos são armazenados em cache após a primeira vez que são carregados. Várias chamadas para
require('foo')
não podem fazer com que o código do módulo seja executado várias vezes.
Portanto, parece que cada módulo necessário pode ser facilmente usado como um singleton sem o código-clichê de singleton.
Questão:
O artigo acima fornece uma solução geral para a criação de um singleton?
javascript
node.js
design-patterns
singleton
mkoryak
fonte
fonte
Respostas:
Isso tem basicamente a ver com o cache do nodejs. Claro e simples.
https://nodejs.org/api/modules.html#modules_caching
(v 6.3.1)
Então, em termos simples.
Se você quer um Singleton; exportar um objeto .
Se você não quer um Singleton; exportar uma função (e fazer coisas / retornar coisas / qualquer coisa nessa função).
Para ser MUITO claro, se você fizer isso corretamente, deve funcionar, consulte https://stackoverflow.com/a/33746703/1137669 (resposta de Allen Luce). Ele explica no código o que acontece quando o cache falha devido a nomes de arquivo resolvidos de forma diferente. Mas se você SEMPRE resolver para o mesmo nome de arquivo, ele deve funcionar.
Atualização 2016
criando um verdadeiro singleton em node.js com símbolos es6 Outra solução : neste link
Atualização 2020
Esta resposta se refere a CommonJS (a maneira própria do Node.js para importar / exportar módulos). O Node.js provavelmente mudará para os Módulos ECMAScript : https://nodejs.org/api/esm.html (ECMAScript é o nome real do JavaScript, caso você não saiba)
Ao migrar para ECMAScript, leia o seguinte por enquanto: https://nodejs.org/api/esm.html#esm_writing_dual_packages_while_avoiding_or_minimizing_hazards
fonte
Todas as opções acima são complicadas demais. Há uma escola de pensamento que diz que os padrões de projeto estão mostrando deficiências da linguagem real.
Linguagens com OOP baseado em protótipo (sem classes) não precisam de um padrão singleton. Você simplesmente cria um único objeto (tonelada) na hora e, em seguida, o usa.
Quanto aos módulos no nó, sim, por padrão eles são armazenados em cache, mas pode ser ajustado, por exemplo, se você quiser o carregamento a quente das alterações do módulo.
Mas sim, se você quiser usar o objeto compartilhado todo, colocá-lo em um módulo de exportação é bom. Só não complique com "padrão singleton", não há necessidade dele em JavaScript.
fonte
There is a school of thought which says design patterns are showing deficiencies of actual language.
Não. Quando o cache do módulo do Node falha, esse padrão singleton falha. Modifiquei o exemplo para executar significativamente no OSX:
Isso dá a saída que o autor antecipou:
Mas uma pequena modificação anula o cache. No OSX, faça o seguinte:
Ou, no Linux:
Em seguida, altere a
sg2
linha necessária para:E bam , o singleton é derrotado:
Não sei de uma maneira aceitável de contornar isso. Se você realmente sente a necessidade de fazer algo parecido com um singleton e não tem problema em poluir o namespace global (e os muitos problemas que podem resultar), você pode alterar o autor
getInstance()
e asexports
linhas para:Dito isso, nunca me deparei com uma situação em um sistema de produção em que precisasse fazer algo assim. Também nunca senti a necessidade de usar o padrão singleton em Javascript.
fonte
Olhando um pouco mais adiante, nas advertências de cache do módulo nos documentos dos módulos:
Portanto, dependendo de onde você está quando precisa de um módulo, é possível obter uma instância diferente do módulo.
Parece que os módulos não são uma solução simples para a criação de singletons.
Edit: Ou talvez sejam . Como @mkoryak, não consigo pensar em um caso em que um único arquivo possa resolver para nomes de arquivo diferentes (sem usar links simbólicos). Mas (como comentários de @JohnnyHK), várias cópias de um arquivo em
node_modules
diretórios diferentes serão carregadas e armazenadas separadamente.fonte
node_modules
quais cada um depende do mesmo módulo, mas há cópias separadas desse módulo dependente nonode_modules
subdiretório de cada um dos dois módulos diferentes.require('./db')
está em dois arquivos separados, o código para odb
módulo é executado duas vezesrequire('../lib/myModule.js');
em um arquivo erequire('../lib/mymodule.js');
em outro e não entregou o mesmo objeto.Um singleton no node.js (ou no navegador JS, nesse caso) como esse é completamente desnecessário.
Como os módulos são armazenados em cache e com estado, o exemplo fornecido no link que você forneceu poderia ser facilmente reescrito de forma muito mais simples:
fonte
may not
se aplica quando vocênpm link
outros módulos durante o desenvolvimento. Portanto, tome cuidado ao usar módulos que dependem de uma única instância, como um eventBus.A única resposta aqui que usa classes ES6
requer este singleton com:
O único problema aqui é que você não pode passar parâmetros para o construtor da classe, mas isso pode ser contornado chamando manualmente um
init
método.fonte
summary
em outra classe, sem inicializá-la novamente?Você não precisa de nada especial para fazer um singleton em js, o código no artigo também poderia ser:
Fora de node.js (por exemplo, no navegador js), você precisa adicionar a função de wrapper manualmente (isso é feito automaticamente em node.js):
fonte
Singletons são bons em JS, mas não precisam ser tão prolixos.
No nó, se você precisar de um singleton, por exemplo, para usar a mesma instância ORM / DB em vários arquivos em sua camada de servidor, você pode colocar a referência em uma variável global.
Basta escrever um módulo que cria a var global, se ela não existir, e retorna uma referência a ela.
@ allen-luce acertou com seu exemplo de código de nota de rodapé copiado aqui:
mas é importante notar que usar a
new
palavra-chave não é obrigatório. Qualquer objeto, função, vida, etc. antigo funcionará - não há vodu OOP acontecendo aqui.pontos de bônus se você fechar um algum obj dentro de uma função que retorna uma referência a ele e tornar essa função global - mesmo a reatribuição da variável global não afetará as instâncias já criadas a partir dela - embora isso seja questionavelmente útil.
fonte
module.exports = new Foo()
porque module.exports não será executado novamente, a menos que você faça algo realmente estúpidoMantendo as coisas simples.
foo.js
Então só
fonte