首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >nodejs中的单例模式-需要吗?

nodejs中的单例模式-需要吗?
EN

Stack Overflow用户
提问于 2012-11-01 22:23:36
回答 10查看 93.8K关注 0票数 106

我最近遇到了关于如何在Node.js中编写单例的this article。我知道require states的文档是:

模块在第一次加载后被缓存。对require('foo')的多次调用可能不会导致模块代码多次执行。

因此,似乎每个所需的模块都可以很容易地作为一个单例使用,而不需要单例样板代码。

问题:

上面的文章提供了创建单例的解决方案吗?

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2016-08-10 21:31:37

这基本上与nodejs缓存有关。简单明了。

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

(v 6.3.1)

缓存

模块在第一次加载后被缓存。这意味着(在其他事情中),每次对require('foo')的调用都将得到完全相同的对象返回,如果它将解析到相同的文件。

对require('foo')的多次调用可能不会导致模块代码多次执行。这是一个重要的特性。有了它,可以返回“部分完成”的对象,从而允许加载传递依赖,即使它们会导致循环。

如果您想让一个模块多次执行代码,那么导出一个函数,然后调用该函数。

模块缓存注意事项

模块根据其解析的文件名进行缓存。由于模块可能会根据调用模块的位置解析为不同的文件名(从node_modules文件夹加载),因此不能保证require('foo')将始终返回完全相同的对象,如果它将解析为不同的文件。

此外,在不区分大小写的文件系统或操作系统上,不同的解析文件名可以指向相同的文件,但缓存仍会将它们视为不同的模块,并会多次重新加载文件。例如,require(' ./foo ')和require(' ./FOO ')返回两个不同的对象,而不管./FOO和./FOO是否是同一个文件。

所以简而言之。

如果需要单例;,请导出对象

如果您不想要单例;导出一个函数(并在该函数中执行填充/返回填充/其他操作)。

非常清楚的是,如果你正确地这样做,它应该可以工作,看看 (Allen Luce的答案)。它在代码中解释了当缓存由于不同解析的文件名而失败时会发生什么。但是,如果您总是解析到相同的文件名,它应该可以工作。

更新2016

creating a true singleton in node.js with es6 symbols Another solutionin this link

更新2020

这个答案指的是CommonJS (Node.js自己的导入/导出模块的方式)。Node.js很可能会切换到ECMAScript模块https://nodejs.org/api/esm.html (如果你不知道,ECMAScript是JavaScript的真实名称)

现在迁移到ECMAScript时,请阅读以下内容:https://nodejs.org/api/esm.html#esm_writing_dual_packages_while_avoiding_or_minimizing_hazards

票数 66
EN

Stack Overflow用户

发布于 2012-11-01 22:35:58

以上所有这些都过于复杂了。有一种思想流派认为,设计模式显示了实际语言的缺陷。

具有基于原型的OOP (无类)的语言根本不需要单例模式。您只需动态创建一个(Ton)对象,然后使用它。

至于节点中的模块,是的,默认情况下它们是缓存的,但它可以进行调整,例如,如果您想要热加载模块更改。

但是,是的,如果你想在所有地方使用共享对象,把它放在一个模块导出中是可以的。只是不要用“单例模式”来复杂化它,在JavaScript中不需要它。

票数 143
EN

Stack Overflow用户

发布于 2015-11-17 07:45:43

No。当节点的模块缓存失败时,单例模式也会失败。我修改了示例,以便在OSX上有意义地运行:

代码语言:javascript
复制
var sg = require("./singleton.js");
var sg2 = require("./singleton.js");
sg.add(1, "test");
sg2.add(2, "test2");

console.log(sg.getSocketList(), sg2.getSocketList());

这给出了作者预期的输出:

代码语言:javascript
复制
{ '1': 'test', '2': 'test2' } { '1': 'test', '2': 'test2' }

但是一个小小的修改就能击败缓存。在OSX上,执行以下操作:

代码语言:javascript
复制
var sg = require("./singleton.js");
var sg2 = require("./SINGLETON.js");
sg.add(1, "test");
sg2.add(2, "test2");

console.log(sg.getSocketList(), sg2.getSocketList());

或者,在Linux上:

代码语言:javascript
复制
% ln singleton.js singleton2.js

然后将sg2 require行更改为:

代码语言:javascript
复制
var sg2 = require("./singleton2.js");

然后砰的一声,独生子被击败了:

代码语言:javascript
复制
{ '1': 'test' } { '2': 'test2' }

我不知道有什么可以接受的方法来解决这个问题。如果您确实觉得有必要制作类似于单例的东西,并且可以接受污染全局名称空间(以及可能导致的许多问题),那么可以将作者的getInstance()exports行更改为:

代码语言:javascript
复制
singleton.getInstance = function(){
  if(global.singleton_instance === undefined)
    global.singleton_instance = new singleton();
  return global.singleton_instance;
}

module.exports = singleton.getInstance();

也就是说,我从来没有在生产系统中遇到过需要这样做的情况。我也从来没有觉得有必要在Javascript中使用单例模式。

票数 29
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13179109

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档