问题描述
我最近遇到本文如何在node.js中写单身我知道require state:
模块被缓存. require('foo')的多个调用可能不会导致模块代码多次执行. 因此,似乎每个必需的模块都可以轻松用作无singleton样板代码的单身. 问题: 上面的文章是否提供了有关创建单例的解决方案的回合? https://nodejs.org/api/modules.html#modules_caching
(v 6.3.1) 模块被缓存.这意味着
(除其他外)每个需要的要求('foo')都会得到
完全返回的对象,如果将其解析为同一对象
文件. 多个需要的呼叫('foo')可能不会导致模块代码为
执行多次.这是一个重要功能.用它,
可以返回"部分完成"对象,从而允许传递
即使在引起周期的情况下也要加载依赖项. 如果要多次执行模块执行代码,则导出
函数,并调用该功能. 模块根据其解决的文件名缓存.由于模块可能
根据呼叫的位置解决其他文件名
模块(从node_modules文件夹加载),不能保证
require('foo')总是会返回完全相同的对象
解析到不同的文件. 此外,在对案例不敏感的文件系统或操作系统上,
不同的解决文件名可以指向同一文件,但是缓存
仍然将它们视为不同的模块,并将重新加载文件
多次.例如,需要('./foo')和需要('./foo')
返回两个不同的对象,无论是否为./foo和
./foo是同一文件. 所以简单地说. 如果您想要单身人士; 导出一个对象. 如果您不想要单身人士; 导出功能(并在该功能中做任何东西/返回的东西/任何内容). 要非常清楚,如果您这样做应该可以起作用,请查看 https://stackoverflow.com/A/33746703/1137669 (Allen Luce的答案).它在代码中解释了由于已解决的文件名而导致缓存失败时发生的情况.但是,如果您始终解决相同的文件名,它应该起作用. 创建带有ES6符号的Node.js中的一个真正的单例
另一个解决方案:在此链接中/p>
此答案是指 commonjs (node.js自己的导入/导出模块的方式). node.js很可能会切换到 ecmascript模块: https://nodejs .org/api/esm.html (如果您不知道,ecmascript是JavaScript的真实姓名) 迁移到ecmascript时,现在暂时阅读以下内容: esm.html#esm_writing_dual_packages_while_avoiding_or_minimizing_hazards 上述所有内容都过复杂.有一个思想流派说设计模式显示出实际语言的缺陷. 具有基于原型的OOP(无类)的语言根本不需要单例图案.您只需即时创建一个单个(TON)对象,然后使用它. 至于节点中的模块,是的,默认情况下它们是缓存的,但是可以对其进行调整.
但是,是的,如果您想全面使用共享对象,则将其放入模块导出是可以的.只是不要将其复杂化,而在JavaScript中不需要它. no.当节点的模块缓存失败时,单身模式会失败.我修改了示例以在OSX上有意义地运行: 这给了作者预期的输出: 但是,一个小的修改击败了缓存.在OSX上,执行此操作: 或,在Linux上: 然后更改sg2要求行为: 和 bam ,单身人士被击败: 我不知道可以接受的方法.如果您确实觉得需要制作类似单身的东西,并且可以污染全局名称空间(以及可能导致的许多问题),则可以将作者的getInstance()和exports行更改为: 也就是说,我从来没有遇到过生产系统的情况,我需要做这样的事情.我也从来没有觉得需要在JavaScript中使用Singleton图案.
第一次加载后,
推荐答案
这基本上与nodejs缓存有关.简单而简单.
缓存
第一次加载后,模块缓存警告
更新2016
更新2020
其他推荐答案
其他推荐答案
var sg = require("./singleton.js");
var sg2 = require("./singleton.js");
sg.add(1, "test");
sg2.add(2, "test2");
console.log(sg.getSocketList(), sg2.getSocketList());
{ '1': 'test', '2': 'test2' } { '1': 'test', '2': 'test2' }
var sg = require("./singleton.js");
var sg2 = require("./SINGLETON.js");
sg.add(1, "test");
sg2.add(2, "test2");
console.log(sg.getSocketList(), sg2.getSocketList());
% ln singleton.js singleton2.js
var sg2 = require("./singleton2.js");
{ '1': 'test' } { '2': 'test2' }
singleton.getInstance = function(){
if(global.singleton_instance === undefined)
global.singleton_instance = new singleton();
return global.singleton_instance;
}
module.exports = singleton.getInstance();
问题描述
I recently came across this article on how to write a singleton in Node.js. I know the documentation of require states that:
Modules are cached after the first time they are loaded. Multiple calls to require('foo') may not cause the module code to be executed multiple times.
So it seems that every required module can be easily used as a singleton without the singleton boilerplate-code.
Question:
Does the above article provide a round about solution to creating a singleton?
推荐答案
This has basically to do with nodejs caching. Plain and simple.
https://nodejs.org/api/modules.html#modules_caching
(v 6.3.1)
Caching
Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.
Multiple calls to require('foo') may not cause the module code to be executed multiple times. This is an important feature. With it, "partially done" objects can be returned, thus allowing transitive dependencies to be loaded even when they would cause cycles.
If you want to have a module execute code multiple times, then export a function, and call that function.
Module Caching Caveats
Modules are cached based on their resolved filename. Since modules may resolve to a different filename based on the location of the calling module (loading from node_modules folders), it is not a guarantee that require('foo') will always return the exact same object, if it would resolve to different files.
Additionally, on case-insensitive file systems or operating systems, different resolved filenames can point to the same file, but the cache will still treat them as different modules and will reload the file multiple times. For example, require('./foo') and require('./FOO') return two different objects, irrespective of whether or not ./foo and ./FOO are the same file.
So in simple terms.
If you want a Singleton; export an object.
If you do not want a Singleton; export a function (and do stuff/return stuff/whatever in that function).
To be VERY clear, if you do this properly it should work, look at https://stackoverflow.com/a/33746703/1137669 (Allen Luce's answer). It explains in code what happens when caching fails due to differently resolved filenames. But if you ALWAYS resolve to the same filename it should work.
Update 2016
creating a true singleton in node.js with es6 symbols Another solution: in this link
Update 2020
This answer refers to CommonJS (Node.js's own way to import/export modules). Node.js will most likely be switching over to ECMAScript Modules: https://nodejs.org/api/esm.html (ECMAScript is the real name of JavaScript if you didn't know)
When migrating to ECMAScript read the following for now: https://nodejs.org/api/esm.html#esm_writing_dual_packages_while_avoiding_or_minimizing_hazards
其他推荐答案
All of the above is overcomplicated. There is a school of thought which says design patterns are showing deficiencies of actual language.
Languages with prototype-based OOP (classless) do not need a singleton pattern at all. You simply create a single(ton) object on the fly and then use it.
As for modules in node, yes, by default they are cached, but it can be tweaked for example if you want hot-loading of module changes.
But yes, if you want to use shared object all over, putting it in a module exports is fine. Just do not complicate it with "singleton pattern", no need for it in JavaScript.
其他推荐答案
No. When Node's module caching fails, that singleton pattern fails. I modified the example to run meaningfully on 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());
This gives the output the author anticipated:
{ '1': 'test', '2': 'test2' } { '1': 'test', '2': 'test2' }
But a small modification defeats caching. On OSX, do this:
var sg = require("./singleton.js"); var sg2 = require("./SINGLETON.js"); sg.add(1, "test"); sg2.add(2, "test2"); console.log(sg.getSocketList(), sg2.getSocketList());
Or, on Linux:
% ln singleton.js singleton2.js
Then change the sg2 require line to:
var sg2 = require("./singleton2.js");
And bam, the singleton is defeated:
{ '1': 'test' } { '2': 'test2' }
I don't know of an acceptable way to get around this. If you really feel the need to make something singleton-like and are okay with polluting the global namespace (and the many problems that can result), you can change the author's getInstance() and exports lines to:
singleton.getInstance = function(){ if(global.singleton_instance === undefined) global.singleton_instance = new singleton(); return global.singleton_instance; } module.exports = singleton.getInstance();
That said, I've never run into a situation on a production system where I needed to do anything like this. I've also never felt the need to use the singleton pattern in Javascript.