नोडज में सिंगलटन पैटर्न - क्या इसकी आवश्यकता है?


95

मैं हाल ही में इस लेख पर आया था कि Node.js. में एक सिंगलटन कैसे लिखा जाता है मुझे पता require है कि राज्यों के प्रलेखन :

पहली बार लोड किए जाने के बाद मॉड्यूल को कैश किया जाता है। कई बार कॉल के require('foo')कारण मॉड्यूल कोड कई बार निष्पादित नहीं हो सकता है।

तो ऐसा लगता है कि हर आवश्यक मॉड्यूल को सिंगलटन के बिना सिंगलटन बॉयलरप्लेट-कोड के रूप में आसानी से इस्तेमाल किया जा सकता है।

सवाल:

क्या उपरोक्त लेख एक सिंगलटन बनाने के समाधान के बारे में एक दौर प्रदान करता है?


1
यहाँ एक 5 मिनट है। इस विषय पर व्याख्या (v6 और npm3 के बाद लिखी गई): medium.com/@lazlojuly/…
lazlojuly

जवाबों:


56

यह मूल रूप से नोडज कैशिंग के साथ करना है। सादा और सरल।

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

(v 6.3.1)

कैशिंग

पहली बार लोड किए जाने के बाद मॉड्यूल को कैश किया जाता है। इसका मतलब है (अन्य चीजों के बीच) कि आवश्यकता के लिए हर कॉल ('फू') को वही वस्तु वापस मिलेगी, यदि वह उसी फ़ाइल को हल करेगी।

आवश्यकता के लिए कई कॉल ('फू') मॉड्यूल कोड को कई बार निष्पादित करने का कारण नहीं हो सकता है। यह एक महत्वपूर्ण विशेषता है। इसके साथ, "आंशिक रूप से किया गया" वस्तुओं को लौटाया जा सकता है, इस प्रकार सकर्मक निर्भरता को तब भी लोड किया जा सकता है जब वे चक्र का कारण बनेंगे।

यदि आप एक मॉड्यूल को कई बार कोड निष्पादित करना चाहते हैं, तो एक फ़ंक्शन निर्यात करें, और उस फ़ंक्शन को कॉल करें।

मॉड्यूल कैशिंग कैविट्स

मॉड्यूल उनके हल किए गए फ़ाइलनाम के आधार पर कैश किए जाते हैं। चूंकि मॉड्यूल कॉलिंग मॉड्यूल (नोड_मॉडल फ़ोल्डर से लोड) के स्थान के आधार पर एक अलग फ़ाइलनाम का समाधान कर सकता है, यह गारंटी नहीं है कि आवश्यकता ('फू') हमेशा एक ही वस्तु को लौटाएगी, यदि यह अलग-अलग फ़ाइलों का समाधान करेगा ।

इसके अतिरिक्त, केस-असंवेदनशील फ़ाइल सिस्टम या ऑपरेटिंग सिस्टम पर, विभिन्न हल किए गए फ़ाइल नाम एक ही फ़ाइल को इंगित कर सकते हैं, लेकिन कैश अभी भी उन्हें अलग-अलग मॉड्यूल के रूप में मानेंगे और फ़ाइल को कई बार पुनः लोड करेंगे। उदाहरण के लिए, आवश्यकता ('./ फू') और आवश्यकता होती है ('./ FOO') दो अलग-अलग ऑब्जेक्ट लौटाते हैं, भले ही वह हो या न हो ।/foo और ./FOO एक ही फाइल हैं।

तो सरल शब्दों में।

यदि आप एक सिंगलटन चाहते हैं; एक वस्तु निर्यात करें

यदि आप एक सिंगलटन नहीं चाहते हैं; एक फंक्शन को एक्सपोर्ट करें (और उस फंक्शन में स्टफ / रिटर्न सामान / जो भी हो) करें।

बहुत स्पष्ट होने के लिए, यदि आप इसे ठीक से करते हैं तो यह काम करना चाहिए, https://stackoverflow.com/a/33746703/1137669 (एलन लुस का उत्तर) देखें। यह कोड में बताता है कि अलग-अलग हल किए गए फ़ाइलनामों के कारण कैशिंग विफल होने पर क्या होता है। लेकिन अगर आप हमेशा एक ही फ़ाइल नाम के लिए काम करते हैं, तो यह काम करना चाहिए।

अपडेट २०१६

इस लिंक में एक और समाधान : es6 प्रतीकों के साथ नोड में एक सच्चे सिंगलटन बनाना

अद्यतन 2020

यह उत्तर कॉमनजेएस (आयात / निर्यात मॉड्यूल के लिए Node.js का अपना तरीका) को संदर्भित करता है । Node.js को संभवतः ECMAScript मॉड्यूल पर स्विच करना होगा : https://nodejs.org/api/esm.html (यदि आप नहीं जानते तो ECMAScript जावास्क्रिप्ट का वास्तविक नाम है)

जब ECMAScript पर माइग्रेट हो रहा है, तो अभी के लिए निम्नलिखित पढ़ें: https://nodejs.org/api/esm.html#esm_writing_dual_packages_ORE_avoiding_or_minimizing_hazards


3
यदि आप एक सिंगलटन चाहते हैं; एक वस्तु का निर्यात करें ... जिसने धन्यवाद की मदद की
danday74

1
यह एक बुरा विचार है - इस पृष्ठ पर कहीं और दिए गए कई कारणों से - लेकिन अवधारणा अनिवार्य रूप से वैध है, जो यह कहना है कि स्थापित नाममात्र परिस्थितियों में, इस उत्तर में दावे सत्य हैं। यदि आप एक त्वरित और गंदे सिंगलटन चाहते हैं, तो यह काम करेगा - कोड के साथ बस किसी भी शटल को लॉन्च न करें।
एडम टॉली

@AdamTolley "इस पृष्ठ पर कहीं और दिए गए कई कारणों से", क्या आप सहानुभूति वाली फ़ाइलों या गलत वर्तनी वाले नामों का उल्लेख कर रहे हैं जो स्पष्ट रूप से एक ही कैश का उपयोग नहीं करते हैं? यह केस-असंवेदनशील फ़ाइल सिस्टम या ऑपरेटिंग सिस्टम के बारे में दस्तावेज़ में स्थिति बताता है। सिम्लिंकिंग के बारे में, आप यहाँ और अधिक पढ़ सकते हैं क्योंकि इसमें github.com/nodejs/node/issues/40402 पर चर्चा की गई थी । यदि आप फ़ाइलों को सहानुभूति दे रहे हैं या अपने ओएस और नोड को ठीक से नहीं समझते हैं, तो आपको एयरोस्पेस इंजीनियरिंग उद्योग के पास कहीं भी नहीं होना चाहिए;), लेकिन मुझे आपकी बात समझ में नहीं आती ^ ^।
के - एसओ में विषाक्तता बढ़ रही है।

@ कर्लमोरिसन - सिर्फ इस तथ्य के लिए कि दस्तावेज़ीकरण इसकी गारंटी नहीं देता है, यह तथ्य कि यह अनिर्दिष्ट व्यवहार प्रतीत होता है, या भाषा के इस विशेष व्यवहार पर भरोसा न करने का कोई अन्य तर्कसंगत कारण है। हो सकता है कि कैश किसी अन्य कार्यान्वयन में अलग तरह से काम करता है, या आप REPL में काम करना पसंद करते हैं और कैशिंग सुविधा को पूरी तरह से हटा देते हैं। मेरा कहना है कि कैश एक कार्यान्वयन विवरण है, और यह एक सिंगलटन समतुल्य एक चतुर हैक के रूप में उपयोग करता है। मुझे चतुर हैक्स पसंद हैं, लेकिन उन्हें विभेदित किया जाना चाहिए, वह सब है - (यह भी कि कोई भी नोड के साथ शटल लॉन्च नहीं कर रहा है, मैं मूर्खतापूर्ण था)
एडम टोली

136

उपरोक्त सभी अतिव्याप्त हैं। विचार का एक स्कूल है जो कहता है कि डिजाइन पैटर्न वास्तविक भाषा की कमियों को दिखा रहे हैं।

प्रोटोटाइप-आधारित ओओपी (क्लासलेस) वाली भाषाओं को एक सिंगलटन पैटर्न की आवश्यकता नहीं है। आप बस मक्खी पर एक (टन) ऑब्जेक्ट बनाते हैं और फिर इसका उपयोग करते हैं।

नोड में मॉड्यूल के लिए के रूप में, हाँ, डिफ़ॉल्ट रूप से वे कैश हैं, लेकिन यह उदाहरण के लिए यदि आप मॉड्यूल परिवर्तनों के गर्म-लोडिंग चाहते हैं के लिए tweaked किया जा सकता है।

लेकिन हाँ, यदि आप सभी साझा ऑब्जेक्ट का उपयोग करना चाहते हैं, तो इसे मॉड्यूल निर्यात में डालना ठीक है। बस इसे "सिंगलटन पैटर्न" के साथ जटिल न करें, जावास्क्रिप्ट में इसके लिए कोई ज़रूरत नहीं है।


27
यह अजीब है किसी का There is a school of thought which says design patterns are showing deficiencies of actual language.
उठना

64
सिंगलेट्स एक प्रतिमान नहीं हैं।
wprl

4
@herby, सिंगलटन पैटर्न की अति-विशिष्ट (और इसलिए गलत) परिभाषा की तरह लगता है।
21

19
दस्तावेज़ पढ़ता है: "कई कॉल करने की आवश्यकता ('फू') के कारण कई बार मॉड्यूल कोड निष्पादित नहीं हो सकता है।" यह "हो सकता है" कहता है, यह "नहीं होगा" नहीं कहता है, इसलिए यह सुनिश्चित करना कि मॉड्यूल का उदाहरण केवल एक बार ही बनाया जाता है कि एक आवेदन में मेरे दृष्टिकोण से एक वैध प्रश्न है।
xorcus

9
यह भ्रामक है कि यह इस प्रश्न का सही उत्तर है। जैसा कि @mike ने नीचे बताया है, यह संभव है कि एक मॉड्यूल एक से अधिक बार लोड हो जाता है और आपके पास दो उदाहरण हैं। मैं उस मुद्दे को मार रहा हूं जहां मेरे पास नॉकआउट की केवल एक प्रति है लेकिन दो उदाहरण बनाए गए हैं क्योंकि मॉड्यूल दो बार लोड किया गया है।
डेगविओला

26

नहीं, जब नोड का मॉड्यूल कैशिंग विफल हो जाता है, तो सिंगलटन पैटर्न विफल हो जाता है। मैंने 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());

या, लिनक्स पर:

% ln singleton.js singleton2.js

फिर sg2आवश्यकता रेखा को इसमें बदलें :

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

और बम , सिंगलटन को हराया गया है:

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

मुझे इसके आसपास जाने का एक स्वीकार्य तरीका नहीं पता है। यदि आप वास्तव में कुछ सिंगलटन की तरह बनाने की आवश्यकता महसूस करते हैं और वैश्विक नाम स्थान (और कई समस्याएं जो परिणाम कर सकते हैं) को प्रदूषित करने के साथ ठीक हैं, तो आप लेखक के getInstance()और exportsलाइनों को बदल सकते हैं :

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

module.exports = singleton.getInstance();

उस ने कहा, मैं एक उत्पादन प्रणाली की स्थिति में कभी नहीं चला हूं, जहां मुझे ऐसा कुछ भी करने की आवश्यकता थी। मैंने जावास्क्रिप्ट में सिंगलटन पैटर्न का उपयोग करने की आवश्यकता भी महसूस नहीं की है।


21

मॉड्यूल डॉक्स में मॉड्यूल कैशिंग केट्स पर थोड़ा और देखना :

मॉड्यूल उनके हल किए गए फ़ाइलनाम के आधार पर कैश किए जाते हैं। चूंकि मॉड्यूल कॉलिंग मॉड्यूल (नोड_मॉडल फ़ोल्डर से लोड) के स्थान के आधार पर एक अलग फ़ाइलनाम का समाधान कर सकता है, यह गारंटी नहीं है कि आवश्यकता ('फू') हमेशा एक ही वस्तु को लौटाएगी , यदि यह अलग-अलग फ़ाइलों का समाधान करेगा ।

इसलिए, इस बात पर निर्भर करता है कि जब आप मॉड्यूल की आवश्यकता कर रहे हैं, तो आप मॉड्यूल का एक अलग उदाहरण प्राप्त करना संभव है।

मॉड्यूल की तरह लगता है एकल बनाने के लिए एक सरल समाधान नहीं है।

संपादित करें: या शायद वे हैं । @Mkoryak की तरह, मैं एक ऐसे मामले के साथ नहीं आ सकता जहाँ एक ही फाइल अलग-अलग फ़ाइलनामों (सिम्बलिंक का उपयोग किए बिना) को हल कर सकती है। लेकिन (@JohnnyHK टिप्पणियों के रूप में), अलग-अलग node_modulesनिर्देशिकाओं में एक फ़ाइल की कई प्रतियां प्रत्येक को अलग से लोड और संग्रहीत किया जाएगा।


ठीक है, मैंने पढ़ा है कि 3 बार और मैं अभी भी एक उदाहरण पर नहीं सोच सकता कि यह एक अलग फ़ाइल नाम पर कैसे हल होगा। मदद?
mkoryak

1
@mkoryak मुझे लगता है कि ऐसे मामलों का जिक्र है जहां आपको दो अलग-अलग मॉड्यूल मिले node_modulesहैं जिनकी आपको आवश्यकता होती है जहां से प्रत्येक एक ही मॉड्यूल पर निर्भर करता है, लेकिन node_modulesदो अलग-अलग मॉड्यूलों में से प्रत्येक के उपनिर्देशिका के तहत उस निर्भर मॉड्यूल की अलग-अलग प्रतियां हैं ।
जॉनीएचके

@ आप यहीं हैं कि अलग-अलग रास्तों से संदर्भित होने पर मॉड्यूल को कई बार त्वरित रूप से प्राप्त होता है। सर्वर मॉड्यूल के लिए इकाई परीक्षण लिखते समय मैंने मामले को मारा। मुझे एक प्रकार की सिंगलटन आवृत्ति की आवश्यकता है। उसकी प्राप्ति कैसे हो?
सुशील

एक उदाहरण सापेक्ष पथ हो सकता है। जैसे। यह देखते हुए require('./db')कि दो अलग-अलग फ़ाइलों में है, dbमॉड्यूल के लिए कोड दो बार निष्पादित होता है
विलोपित

9
मैं सिर्फ एक बुरा बग था क्योंकि नोड मॉड्यूल सिस्टम केस-इन्सेंस्टीवी है। मैंने require('../lib/myModule.js');एक फ़ाइल में और require('../lib/mymodule.js');दूसरे में कॉल किया और यह एक ही ऑब्जेक्ट डिलीवर नहीं करता था।
उत्तरायण

18

नोड.जेएस (या ब्राउज़र जेएस, उस मामले के लिए) में एक सिंगलटन पूरी तरह से अनावश्यक है।

चूंकि मॉड्यूल कैश्ड और स्टेटफुल होते हैं, इसलिए आपके द्वारा दिए गए लिंक पर दिए गए उदाहरण को आसानी से बहुत आसानी से लिखा जा सकता है:

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

5
डॉक्स कहते हैं कि " नहीं हो सकता है , तो यह संभव है कि इसे कई बार बुलाया जाएगा, और यदि इस कोड को फिर से मार डाला जाता है, socketList एक खाली सूची पर रीसेट हो जाएगा मॉड्यूल कोड कई बार निष्पादित करने के लिए कारण"
जोनाथन।

3
@Jonathan। उस उद्धरण के आस-पास के दस्तावेज़ों में संदर्भ एक बहुत ही आश्वस्त करने वाला मामला प्रतीत होता है जिसका उपयोग RFC- शैली MUST NOT में नहीं किया जा सकता है ।
माइकल

6
@Michael "may" एक मजाकिया शब्द है जैसे। फैंसी एक शब्द है कि जब नकारात्मक मतलब है या तो "शायद नहीं" या "निश्चित रूप से नहीं" ..
OJFord

1
may notलागू होता है जब आप npm linkविकास के दौरान अन्य मॉड्यूल। इसलिए मॉड्यूल का उपयोग करते समय सावधान रहें जो एक इवेंट जैसे कि इवेंटबस पर भरोसा करते हैं।
20

10

यहाँ एकमात्र उत्तर है जो ES6 कक्षाओं का उपयोग करता है

// SummaryModule.js
class Summary {

  init(summary) {
    this.summary = summary
  }

  anotherMethod() {
    // do something
  }
}

module.exports = new Summary()

इसके साथ इस सिंगलटन की आवश्यकता है:

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

यहाँ केवल समस्या यह है कि आप क्लास कंस्ट्रक्टर को पास नहीं कर सकते हैं, लेकिन एक initविधि को मैन्युअल रूप से कॉल करके इसे दरकिनार किया जा सकता है ।


सवाल यह है कि "सिंगलटन की जरूरत है", न कि "आप कैसे लिखते हैं"
mkoryak

@ danday74 summaryफिर से इनिशियलाइज़ किए बिना हम उसी उदाहरण को दूसरी कक्षा में कैसे उपयोग कर सकते हैं ?
एम फैसल हमीद

1
Node.js में बस इसे किसी अन्य फ़ाइल में आवश्यक है ... const सारांश = आवश्यकता ('./ सारांश सारांश') ... और यह एक ही उदाहरण होगा। आप इसे एक सदस्य चर बनाकर और एक फ़ाइल में इसके मूल्य को सेट करके और इसके बाद किसी अन्य फ़ाइल में इसका मान प्राप्त करके इसकी आवश्यकता का परीक्षण कर सकते हैं। यह वह मान होना चाहिए जो सेट किया गया था।
danday74

9

आपको js में सिंगलटन करने के लिए कुछ विशेष करने की आवश्यकता नहीं है, लेख में कोड बस हो सकता है:

var socketList = {};

module.exports = {
      add: function() {

      },

      ...
};

नोड से बाहर। जेएस (उदाहरण के लिए, ब्राउज़र जेएस में), आपको रैपर फ़ंक्शन को मैन्युअल रूप से जोड़ना होगा (यह नोड में स्वचालित रूप से किया जाता है। जेएस):

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

जैसा कि @Allen Luce द्वारा बताया गया है, अगर नोड का कैचिंग विफल रहता है तो सिंगलटन पैटर्न भी विफल हो जाता है।
राकेन 13:17

6

जेएस में सिंगलटन ठीक हैं, उन्हें सिर्फ इतना वर्बोस होने की जरूरत नहीं है।

नोड में यदि आपको एक सिंगलटन की आवश्यकता है, उदाहरण के लिए अपने सर्वर परत में विभिन्न फाइलों में एक ही ORM / DB उदाहरण का उपयोग करने के लिए, आप संदर्भ को एक वैश्विक चर में भर सकते हैं।

बस एक मॉड्यूल लिखें जो वैश्विक संस्करण बनाता है यदि यह मौजूद नहीं है, तो उसी का संदर्भ देता है।

@ एलन-लूस ने इसे अपने फुटनोट कोड उदाहरण के साथ यहां कॉपी किया था:

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

module.exports = singleton.getInstance();

लेकिन यह ध्यान रखना महत्वपूर्ण है कि newकीवर्ड का उपयोग करना आवश्यक नहीं है। कोई भी पुरानी वस्तु, फंक्शन, आईलाइफ इत्यादि काम करेगा - यहाँ कोई OOP वूडू नहीं है।

बोनस अंक यदि आप किसी फ़ंक्शन के अंदर कुछ obj को बंद करते हैं, जो इसके लिए एक संदर्भ देता है, और उस फ़ंक्शन को एक वैश्विक बनाता है - तो वैश्विक चर का पुनर्मूल्यांकन भी पहले से निर्मित इंस्टेंस को क्लोब नहीं करेगा - हालांकि यह संदिग्ध रूप से उपयोगी है।


आपको उसकी कोई जरूरत नहीं है। आप सिर्फ module.exports = new Foo()इसलिए कर सकते हैं क्योंकि मॉड्यूल.एक्सपोर्ट्स फिर से निष्पादित नहीं करेंगे, जब तक कि आप वास्तव में बेवकूफ कुछ नहीं करते हैं
mkoryak

आपको पूरी तरह से कार्यान्वयन के दुष्प्रभावों पर भरोसा नहीं करना चाहिए। यदि आपको एक एकल उदाहरण की आवश्यकता है, तो इसे लागू करने के मामले में, इसे वैश्विक रूप से बाँध लें।
एडम टोले

उपर्युक्त उत्तर भी मूल प्रश्न की गलतफहमी थी कि 'क्या मुझे जेएस में सिंगलटन का उपयोग करना चाहिए या क्या भाषा उन्हें अनावश्यक बनाती है?', जो कि बहुत सारे अन्य उत्तरों के साथ एक मुद्दा भी लगता है। मैं उचित, स्पष्ट सिंगलटन कार्यान्वयन के प्रतिस्थापन की आवश्यकता के उपयोग के खिलाफ अपनी सिफारिश के साथ खड़ा हूं।
एडम टोली

1

इसे सरल रखना।

foo.js

function foo() {

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

  return bar;
};

module.exports = foo();

फिर बस

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

सवाल यह है कि "क्या
एकल गीतों की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.