code

nodejs의 싱글 톤 패턴-필요합니까?

codestyles 2020. 9. 15. 07:50
반응형

nodejs의 싱글 톤 패턴-필요합니까?


최근 에 Node.js에서 싱글 톤을 작성하는 방법에 대한 이 기사 를 보았습니다. 다음과 같은 require 상태 문서를 알고 있습니다 .

모듈은 처음로드 된 후 캐시됩니다. 를 여러 번 호출 require('foo')하면 모듈 코드가 여러 번 실행되지 않을 수 있습니다.

따라서 필요한 모든 모듈은 단일 상용구 코드없이 단일 항목으로 쉽게 사용할 수있는 것 같습니다.

질문:

위의 기사가 싱글 톤 생성에 대한 해결책을 제공합니까?


이것은 기본적으로 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가 동일한 파일인지 여부에 관계없이 두 개의 다른 객체를 반환합니다.

그래서 간단히 말해서.

싱글 톤을 원한다면; 개체를 내 보냅니다 .

싱글 톤을 원하지 않는다면; 함수를 내보내십시오 (그리고 그 함수에서 물건을 / 물건을 돌려 보내십시오 / 무엇이든).

명확하게 말하면 제대로 작동하면 https://stackoverflow.com/a/33746703/1137669 (Allen Luce의 답변)를 참조하십시오. 다르게 확인 된 파일 이름으로 인해 캐싱이 실패 할 때 발생하는 상황을 코드에서 설명합니다. 그러나 항상 동일한 파일 이름으로 확인하면 작동합니다.


위의 모든 것은 너무 복잡합니다. 디자인 패턴이 실제 언어의 결함을 보여주고 있다는 생각의 학교가 있습니다.

프로토 타입 기반 OOP (클래스리스)를 사용하는 언어에는 싱글 톤 패턴이 전혀 필요하지 않습니다. 즉석에서 단일 (톤) 개체를 만든 다음 사용하면됩니다.

노드의 모듈은 기본적으로 캐시되지만, 예를 들어 모듈 변경 사항의 핫 로딩을 원하는 경우 조정할 수 있습니다.

그러나 예, 공유 객체를 전체적으로 사용하려면 모듈 내보내기에 넣는 것이 좋습니다. "단일 패턴"으로 복잡하게 만들지 마십시오. JavaScript에서는 필요하지 않습니다.


아니요. Node의 모듈 캐싱이 실패하면 해당 싱글 톤 패턴이 실패합니다. 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());

이것은 작성자가 예상 한 결과를 제공합니다.

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

그러나 약간의 수정은 캐싱을 무효화합니다. 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());

또는 Linux에서 :

% ln singleton.js singleton2.js

그런 다음 sg2require 라인을 다음과 같이 변경하십시오 .

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

그리고 bam , 싱글 톤이 패배합니다.

{ '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.


Looking a little further at the Module Caching Caveats in the Modules docs:

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.

So, depending on where you are when you're requiring a module, it's possible to get a different instance of the module.

Sounds like modules are not a simple solution to creating singletons.

Edit: Or maybe they are. Like @mkoryak, I can't come up with a case where a single file might resolve to different filenames (without using symlinks). But (as @JohnnyHK comments), multiple copies of a file in different node_modules directories will each be loaded and stored separately.


A singleton in node.js (or in browser JS, for that matter) like that is completely unnecessary.

Since modules are cached and stateful, the example given on the link you provided could easily be rewritten much more simply:

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

You don't need anything special to do a singleton in js, the code in the article could just as well be:

var socketList = {};

module.exports = {
      add: function() {

      },

      ...
};

Outside node.js (for instance, in browser js), you need to add the wrapper function manually (it is done automatically in node.js):

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

The only answer here that uses ES6 classes

// SummaryModule.js
class Summary {

  init(summary) {
    this.summary = summary
  }

  anotherMethod() {
    // do something
  }
}

module.exports = new Summary()

require this singleton with:

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

Only problem here is that you cannot pass params to the class constructor but that can be circumvented by manually calling an init method.


Singletons are fine in JS, they just don't need to be so verbose.

In node if you need a singleton, for instance to use the same ORM/DB instance across various files in your server layer, you can stuff the reference into a global variable.

Just write a module that creates the global var if it doesn't exist, then returns a reference to that.

@allen-luce had it right with his footnote code example copied here:

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

module.exports = singleton.getInstance();

but it is important to note that using the new keyword is not required. Any old object, function, iife, etc. will work - there is no OOP voodoo happening here.

bonus points if you closure a some obj inside a function that returns a reference to it, and make that function a global - then even reassignment of the global variable won't clobber the instances already created from it - though this is questionably useful.


Keeping it simple.

foo.js

function foo() {

  bar: {
    doSomething: function(arg, callback) {
      return callback('Echo ' + arg);
    };
  }

  return bar;
};

module.exports = foo();

Then just

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

참고URL : https://stackoverflow.com/questions/13179109/singleton-pattern-in-nodejs-is-it-needed

반응형