क्या मुझे NodeJS में निर्भरता इंजेक्शन की आवश्यकता है, या कैसे निपटना है ...?


219

मैं वर्तमान में नोडज के साथ कुछ प्रायोगिक परियोजनाएं बना रहा हूं। मैंने स्प्रिंग के साथ बहुत सारे जावा ईई वेब अनुप्रयोगों को प्रोग्राम किया है और वहां निर्भरता इंजेक्शन की आसानी की सराहना की है।

अब मैं उत्सुक हूं: मैं नोड के साथ निर्भरता इंजेक्शन कैसे करूं? या: क्या मुझे भी इसकी आवश्यकता है? क्या इसकी जगह अवधारणा है, क्योंकि प्रोग्रामिंग शैली अलग है?

मैं साधारण चीजों के बारे में बात कर रहा हूं, जैसे कि डेटाबेस कनेक्शन ऑब्जेक्ट साझा करना, अब तक, लेकिन मुझे ऐसा समाधान नहीं मिला है जो मुझे संतुष्ट करता हो।


1
क्या आपको DI का उपयोग करने का निर्णय लेना चाहिए, OpenTable ने हाल ही में इसके लिए एक लाइब्रेरी खोली है: github.com/opentable/spur-ioc मैंने इसका उपयोग किया है (मैं वहां काम करता हूं), और यह कह सकता हूं कि यह परीक्षण के लिए काफी सरल और बढ़िया है।
tybro0103

जवाबों:


107

संक्षेप में, आपको C # / Java में निर्भरता इंजेक्शन कंटेनर या सर्विस लोकेटर की आवश्यकता नहीं है। चूंकि Node.js, का लाभ उठाता है module pattern, इसलिए कंस्ट्रक्टर या प्रॉपर्टी इंजेक्शन का प्रदर्शन करना आवश्यक नहीं है। हालांकि आप अभी भी कर सकते हैं।

जेएस के बारे में महान बात यह है कि आप जो कुछ भी चाहते हैं उसे प्राप्त करने के लिए बस कुछ भी संशोधित कर सकते हैं। टेस्टिंग की बात आती है तो यह काम आता है।

निहारना मेरे बहुत ही लंगड़े उदाहरण से जुड़ा है।

MyClass.js:

var fs = require('fs');

MyClass.prototype.errorFileExists = function(dir) {
    var dirsOrFiles = fs.readdirSync(dir);
    for (var d in dirsOrFiles) {
        if (d === 'error.txt') return true;
    }
    return false;
};

MyClass.test.js:

describe('MyClass', function(){
    it('should return an error if error.txt is found in the directory', function(done){
        var mc = new MyClass();
        assert(mc.errorFileExists('/tmp/mydir')); //true
    });
});

ध्यान दें कि मॉड्यूल MyClassपर कैसे निर्भर करता है fs? जैसा कि @ShatyemShekhar ने उल्लेख किया है, आप अन्य भाषाओं की तरह वास्तव में कंस्ट्रक्टर या संपत्ति इंजेक्शन कर सकते हैं। लेकिन यह जावास्क्रिप्ट में आवश्यक नहीं है।

इस मामले में, आप दो काम कर सकते हैं।

fs.readdirSyncजब आप कॉल करते हैं तो आप विधि को रोक सकते हैं या पूरी तरह से अलग मॉड्यूल लौटा सकते हैं require

विधि 1:

var oldmethod = fs.readdirSync;
fs.readdirSync = function(dir) { 
    return ['somefile.txt', 'error.txt', 'anotherfile.txt']; 
};

*** PERFORM TEST ***
*** RESTORE METHOD AFTER TEST ****
fs.readddirSync = oldmethod;

विधि 2:

var oldrequire = require
require = function(module) {
    if (module === 'fs') {
        return {
            readdirSync: function(dir) { 
                return ['somefile.txt', 'error.txt', 'anotherfile.txt']; 
            };
        };
    } else
        return oldrequire(module);

}

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

अपडेट करें:

यह डेटाबेस कनेक्शन के बारे में आपके विशिष्ट प्रश्न को संबोधित करना चाहिए। मैं आपके डेटाबेस कनेक्शन लॉजिक को एनक्रिप्ट करने के लिए आपके लिए एक अलग मॉड्यूल बनाऊंगा। कुछ इस तरह:

MyDbConnection.js: (बेहतर नाम चुनना सुनिश्चित करें)

var db = require('whichever_db_vendor_i_use');

module.exports.fetchConnection() = function() {
    //logic to test connection

    //do I want to connection pool?

    //do I need only one connection throughout the lifecyle of my application?

    return db.createConnection(port, host, databasename); //<--- values typically from a config file    
}

फिर, किसी भी मॉड्यूल को डेटाबेस कनेक्शन की आवश्यकता होती है, तो बस अपने MyDbConnectionमॉड्यूल को शामिल करना चाहिए ।

SuperCoolWebApp.js:

var dbCon = require('./lib/mydbconnection'); //wherever the file is stored

//now do something with the connection
var connection = dbCon.fetchConnection(); //mydbconnection.js is responsible for pooling, reusing, whatever your app use case is

//come TEST time of SuperCoolWebApp, you can set the require or return whatever you want, or, like I said, use an actual connection to a TEST database. 

इस उदाहरण को शब्दशः पालन न करें। यह संवाद करने की कोशिश में एक लंगड़ा उदाहरण है कि आप moduleअपनी निर्भरता को प्रबंधित करने के लिए पैटर्न का लाभ उठाते हैं । उम्मीद है कि यह थोड़ा और अधिक मदद करता है।


42
परीक्षण के संबंध में यह सच है, लेकिन DI के अन्य लाभ हैं; DI का उपयोग करके आप एक इंटरफ़ेस पर प्रोग्राम कर सकते हैं, कार्यान्वयन नहीं।
मोटोत्स्क

3
@moteutsch यकीन नहीं है कि जेएस के पास सबसे स्थिर भाषाओं की तरह इंटरफेस की धारणा क्यों नहीं होगी। आप सभी वास्तव में कार्यान्वयन हैं, भले ही आप प्रलेखित "इंटरफ़ेस" पर कुछ पूर्व-सहमति का उपयोग करना चाहते हों।
जेपी रिचर्डसन

16
@JPRichardson मैं एक घटक को कैसे लिख सकता हूं जो किसी एक पुस्तकालय के आधार पर एक लकड़हारे का उपयोग करता है? यदि मैं require('my_logger_library'), मेरे घटक का उपयोग करने वाले लोगों को अपने स्वयं के पुस्तकालय का उपयोग करने की आवश्यकता को ओवरराइड करना होगा। इसके बजाय, मैं लोगों को एक कॉलबैक पास करने की अनुमति दे सकता हूं जो घटकों "निर्माता" या "इनिट" विधि में एक लकड़हारा कार्यान्वयन को लपेटता है। यही डीआई का उद्देश्य है।
moteutsch

4
2014 के मध्य तक - npmjs.org/package/proxyquire मॉकिंग करता है जिससे "निर्भरता" की आवश्यकता होती है।
आर्केल्डन

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

73

requireहै Node.js में निर्भरता के प्रबंधन के लिए जिस तरह से और निश्चित रूप से यह सहज और प्रभावी है, लेकिन यह भी अपनी सीमाएं हैं।

मेरी सलाह है कि आज Node.js के लिए उपलब्ध डिपेंडेंसी इंजेक्शन कंटेनरों में से कुछ पर एक नज़र डालें कि उनके पेशेवरों / विपक्षों पर क्या विचार है। उनमें से कुछ हैं:

कुछ लोगों का नाम बताने के लिए।

अब असली सवाल यह है कि आप एक साधारण की तुलना में Node.js DI कंटेनर से क्या हासिल कर सकते हैं require?

पेशेवरों:

  • बेहतर परीक्षण क्षमता: मॉड्यूल इनपुट के रूप में अपनी निर्भरता स्वीकार करते हैं
  • नियंत्रण का उलटा: अपने आवेदन के मुख्य कोड को छूने के बिना अपने मॉड्यूल को तार करने का निर्णय लें।
  • मॉड्यूल को हल करने के लिए एक अनुकूलन योग्य एल्गोरिथ्म: निर्भरता में "आभासी" पहचानकर्ता होते हैं, आमतौर पर वे फाइल सिस्टम पर एक पथ के लिए बाध्य नहीं होते हैं।
  • बेहतर एक्स्टेंसिबिलिटी: IoC और "वर्चुअल" पहचानकर्ताओं द्वारा सक्षम।
  • अन्य फैंसी सामान संभव:
    • Async आरंभीकरण
    • मॉड्यूल जीवन चक्र प्रबंधन
    • डीआई कंटेनर की व्यापकता ही
    • आसानी से उच्च स्तर के अमूर्त को लागू कर सकते हैं (जैसे AOP)

विपक्ष:

  • Node.js "अनुभव" से अलग: उपयोग नहीं कर रहा है require निश्चित रूप से से ऐसा लगता है जैसे आप सोच के नोड तरीके से भटक रहे हैं।
  • एक निर्भरता और इसके कार्यान्वयन के बीच संबंध हमेशा स्पष्ट नहीं होता है। एक निर्भरता को रनटाइम पर हल किया जा सकता है और विभिन्न मापदंडों से प्रभावित किया जा सकता है। कोड समझना और डीबग करना अधिक कठिन हो जाता है
  • धीमी स्टार्टअप समय
  • परिपक्वता (फिलहाल): वर्तमान समाधानों में से कोई भी इस समय वास्तव में लोकप्रिय नहीं है, इसलिए इतने सारे ट्यूटोरियल नहीं, कोई पारिस्थितिकी तंत्र नहीं, लड़ाई का परीक्षण नहीं।
  • कुछ DI कंटेनर ब्राउजरफाई और वेबपैक जैसे मॉड्यूल बंडलों के साथ अच्छा नहीं खेलेंगे।

सॉफ़्टवेयर विकास से संबंधित किसी भी चीज़ के साथ, DI के बीच चयन करना या requireआपकी आवश्यकताओं, आपके सिस्टम की जटिलता और आपकी प्रोग्रामिंग शैली पर निर्भर करता है।


3
क्या आपको लगता है कि '09 'के बाद से स्थिति काफी बदल गई है?
जूहो वेपसैलीन

13
क्या आपका मतलब 10 दिन पहले से है? :)
मारियो

2
Nooo। 9 दिसंबर ... पता होना चाहिए था।
जुहो वेप्सलीनन

4
मैंने मॉड्यूल "exports = function (deps) {} तरह के पैटर्न का उपयोग करके "DI" लागू किया है। हां, यह काम करता है, लेकिन यह काफी आदर्श नहीं है।
जूहो वेप्सलीनन

3
मॉड्यूल इनपुट के रूप में अपनी निर्भरता स्वीकार करते हैं और निर्भरता मेरे लिए एक विरोधाभास की तरह स्पष्ट नहीं हैं
एंटोन रुडेश्को

53

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

डि # C में

यह समझने के लिए कि DI को जावास्क्रिप्ट में कितनी बड़ी जरूरत नहीं है, यह C # जैसी जोरदार टाइप की गई भाषा को देखने में मददगार है। (उन लोगों से माफी जो सी # नहीं जानते हैं, लेकिन इसका पालन करना आसान होना चाहिए।) मान लीजिए कि हमारे पास एक ऐप है जो कार और उसके हॉर्न का वर्णन करता है। आप दो वर्गों को परिभाषित करेंगे:

class Horn
{
    public void Honk()
    {
        Console.WriteLine("beep!");
    }
}

class Car
{
    private Horn horn;

    public Car()
    {
        this.horn = new Horn();
    }

    public void HonkHorn()
    {
        this.horn.Honk();
    }
}

class Program
{
    static void Main()
    {
        var car = new Car();
        car.HonkHorn();
    }
}

इस तरह कोड लिखने के साथ कुछ समस्याएं हैं।

  1. Carवर्ग कसकर में सींग की विशेष कार्यान्वयन के लिए युग्मित हैHorn वर्ग। अगर हम कार द्वारा उपयोग किए जाने वाले हॉर्न के प्रकार को बदलना चाहते हैं, तो हमें Carक्लास को संशोधित करना होगा, भले ही हॉर्न का उपयोग न बदले। इससे परीक्षण करना भी मुश्किल हो जाता है क्योंकि हम Carकक्षा को उसकी निर्भरता, वर्ग से अलग-थलग नहीं कर सकते Horn
  2. Carवर्ग के जीवन चक्र के लिए जिम्मेदार है Hornवर्ग। इस तरह के एक साधारण उदाहरण में यह एक बड़ा मुद्दा नहीं है, लेकिन वास्तविक अनुप्रयोगों में निर्भरता में निर्भरताएं होंगी, जिनमें निर्भरताएं होंगी, आदि।Car वर्ग को अपनी निर्भरता के पूरे पेड़ को बनाने के लिए जिम्मेदार होने की आवश्यकता होगी। यह न केवल जटिल और दोहराव वाला है, बल्कि यह वर्ग की "एकल जिम्मेदारी" का उल्लंघन करता है। यह एक कार होने पर ध्यान केंद्रित करना चाहिए, उदाहरण नहीं बनाना चाहिए।
  3. समान निर्भरता के उदाहरणों का पुन: उपयोग करने का कोई तरीका नहीं है। फिर, यह इस खिलौना अनुप्रयोग में महत्वपूर्ण नहीं है, लेकिन एक डेटाबेस कनेक्शन पर विचार करें। आपके पास आमतौर पर एक एकल उदाहरण होगा जो आपके आवेदन में साझा किया गया है।

अब, चलो इसे निर्भरता इंजेक्शन पैटर्न का उपयोग करने के लिए रिफ्लेक्टर करते हैं।

interface IHorn
{
    void Honk();
}

class Horn : IHorn
{
    public void Honk()
    {
        Console.WriteLine("beep!");
    }
}

class Car
{
    private IHorn horn;

    public Car(IHorn horn)
    {
        this.horn = horn;
    }

    public void HonkHorn()
    {
        this.horn.Honk();
    }
}

class Program
{
    static void Main()
    {
        var horn = new Horn();
        var car = new Car(horn);
        car.HonkHorn();
    }
}

हमने यहां दो प्रमुख बातें की हैं। सबसे पहले, हमने एक इंटरफ़ेस पेश किया है जो हमारी Hornकक्षा में लागू होता है। यह Carवर्ग को विशेष कार्यान्वयन के बजाय इंटरफ़ेस के लिए कोड देता है । अब कोड कुछ भी ले सकता है जो लागू करता है IHorn। दूसरा, हमने हॉर्न इंस्टेंटेशन को बाहर निकाल दिया हैCar और इसके बजाय इसे पास कर दिया है। यह ऊपर दिए गए मुद्दों को हल करता है और इसे विशिष्ट उदाहरणों और उनके जीवनचक्र को प्रबंधित करने के लिए एप्लिकेशन के मुख्य कार्य पर छोड़ देता है।

इसका मतलब यह है कि कार को छूने के लिए Carवर्ग के बिना उपयोग करने के लिए एक नए प्रकार के सींग का परिचय दे सकता है :

class FrenchHorn : IHorn
{
    public void Honk()
    {
        Console.WriteLine("le beep!");
    }
}

मुख्य FrenchHornइसके बजाय कक्षा के एक उदाहरण को इंजेक्ट कर सकता है । यह भी नाटकीय रूप से परीक्षण को सरल करता है। आप यह MockHornसुनिश्चित करने के लिए Carकंस्ट्रक्टर में इंजेक्ट करने के लिए एक वर्ग बना सकते हैं कि आप बस परीक्षण कर रहे हैंCar अलगाव में कक्षा का ।

ऊपर दिया गया उदाहरण मैनुअल निर्भरता इंजेक्शन दिखाता है। आमतौर पर DI को एक फ्रेमवर्क के साथ किया जाता है (जैसे C # दुनिया में एकता या Ninject )। ये चौखटे आपकी निर्भरता ग्राफ के आधार पर आपके लिए निर्भरता की वायरिंग करेंगे और जरूरत के अनुसार इंस्टेंसेस बनाएंगे।

स्टैण्डर्ड नोड.जेएस वे

अब Node.js. में एक ही उदाहरण देखते हैं। हम शायद अपने कोड को 3 मॉड्यूल में तोड़ेंगे:

// horn.js
module.exports = {
    honk: function () {
        console.log("beep!");
    }
};

// car.js
var horn = require("./horn");
module.exports = {
    honkHorn: function () {
        horn.honk();
    }
};

// index.js
var car = require("./car");
car.honkHorn();

क्योंकि जावास्क्रिप्ट अप्रकाशित है, हमारे पास पहले जैसी ही चुस्त कपलिंग नहीं है। इंटरफेस की कोई आवश्यकता नहीं है (न ही वे मौजूद हैं) क्योंकि carमॉड्यूल बस honkजो कुछ भी है उस पर विधि को कॉल करने का प्रयास करेगाhorn मॉड्यूल निर्यात ।

इसके अतिरिक्त, क्योंकि नोड का requireकैश सब कुछ है, मॉड्यूल अनिवार्य रूप से एक कंटेनर में संग्रहित एकल हैं। कोई अन्य मॉड्यूल जो requireऑन पर कार्य करता हैhorn को सटीक समान उदाहरण मिलेगा। यह डेटाबेस कनेक्शन जैसी एकल वस्तुओं को साझा करना बहुत आसान बनाता है।

अब भी मुद्दा है कि carमॉड्यूल अपनी निर्भरता लाने के लिए जिम्मेदार है horn। यदि आप चाहते थे कि कार अपने हॉर्न के लिए एक अलग मॉड्यूल का उपयोग करे, तो आपको मॉड्यूल requireमें स्टेटमेंट बदलना होगा car। यह करने के लिए एक बहुत ही सामान्य बात नहीं है, लेकिन यह परीक्षण के साथ मुद्दों का कारण बनता है।

लोगों को परीक्षण की समस्या से निपटने का सामान्य तरीका प्रॉक्सीवेर के साथ है । जावास्क्रिप्ट की गतिशील प्रकृति के कारण, प्रॉक्सी आपको कॉल करने और आपके द्वारा प्रदान किए गए किसी भी स्टब्स / मोक्स को वापस करने की आवश्यकता को स्वीकार करता है।

var proxyquire = require('proxyquire');
var hornStub = {
    honk: function () {
        console.log("test beep!");
    }
};

var car = proxyquire('./car', { './horn': hornStub });

// Now make test assertions on car...

यह अधिकांश अनुप्रयोगों के लिए पर्याप्त से अधिक है। अगर यह आपके ऐप के लिए काम करता है तो इसके साथ जाएं। हालाँकि, मेरे अनुभव में जैसे-जैसे एप्लिकेशन बड़े और अधिक जटिल होते जाते हैं, इस तरह कोड बनाए रखना कठिन हो जाता है।

जावास्क्रिप्ट में DI

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

// horn.js
module.exports = function () {
    return {
        honk: function () {
            console.log("beep!");
        }
    };
};

// car.js
module.exports = function (horn) {
    return {
        honkHorn: function () {
            horn.honk();
        }
    };
};

// index.js
var horn = require("./horn")();
var car = require("./car")(horn);
car.honkHorn();

यह बहुत पहले C # विधि के अनुरूप है कि index.jsमॉड्यूल उदाहरण जीवन चक्र और तारों के लिए जिम्मेदार है। यूनिट परीक्षण काफी सरल है क्योंकि आप केवल कार्यों में मोक्स / स्टब्स में पास कर सकते हैं। फिर, अगर यह आपके आवेदन के लिए पर्याप्त है, तो इसके साथ जाएं।

बोलस डीआई फ्रेमवर्क

C # के विपरीत, आपके निर्भरता प्रबंधन के साथ मदद करने के लिए कोई स्थापित मानक DI चौखटे नहीं हैं। एनपीएम रजिस्ट्री में कई रूपरेखाएं हैं, लेकिन व्यापक रूप से किसी को भी गोद नहीं लिया गया है। इनमें से कई विकल्प पहले से ही अन्य उत्तरों में उद्धृत किए गए हैं।

मैं विशेष रूप से उपलब्ध किसी भी विकल्प से खुश नहीं था इसलिए मैंने अपना खुद का नाम बोलस लिखा । Bolus को ऊपर DI शैली में लिखे गए कोड के साथ काम करने के लिए डिज़ाइन किया गया है और यह बहुत DRY और बहुत सरल होने की कोशिश करता है । उपरोक्त समान car.jsऔर horn.jsमॉड्यूल का उपयोग करके , आप index.jsबोल्ट के साथ मॉड्यूल को फिर से लिख सकते हैं :

// index.js
var Injector = require("bolus");
var injector = new Injector();
injector.registerPath("**/*.js");

var car = injector.resolve("car");
car.honkHorn();

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

Bolus वैकल्पिक निर्भरता और परीक्षण ग्लोबल्स जैसी निफ्टी सुविधाओं के एक समूह का समर्थन करता है, लेकिन दो मानक लाभ हैं जो मैंने मानक Node.js दृष्टिकोण के सापेक्ष देखे हैं। सबसे पहले, यदि आपके पास बहुत सारे समान अनुप्रयोग हैं, तो आप अपने आधार के लिए एक निजी एनपीएम मॉड्यूल बना सकते हैं जो एक इंजेक्टर बनाता है और उस पर उपयोगी वस्तुओं को पंजीकृत करता है। फिर आपके विशिष्ट एप्लिकेशन जरूरत के अनुसार बहुत कुछ जोड़ सकते हैं, ओवरराइड कर सकते हैं और हल कर सकते हैं AngularJSइंजेक्टर काम करता है। दूसरा, आप निर्भरता के विभिन्न संदर्भों को प्रबंधित करने के लिए बोल्ट का उपयोग कर सकते हैं। उदाहरण के लिए, आप अनुरोध के अनुसार चाइल्ड इंजेक्टर बनाने के लिए मिडलवेयर का उपयोग कर सकते हैं, इंजेक्टर पर यूजर आईडी, सेशन आईडी, लॉगर इत्यादि को पंजीकृत कर सकते हैं, साथ ही उन पर निर्भर करता है। फिर अनुरोधों को पूरा करने के लिए आपको जो चाहिए वह हल करें। यह आपके अनुरोध के अनुसार आपको अपने मॉड्यूल के उदाहरण देता है और हर मॉड्यूल फ़ंक्शन कॉल के साथ लकड़हारा आदि को पास करने से रोकता है।


1
यह भी सच है कि proxyquireइस तरह के विकल्प हैं sinonजो आपको बहुत संक्षिप्त मॉक करने की अनुमति देते हैं, उदाहरण के लिए let readFileStub = sinon.stub(fs, 'readFile').yields(new Error('something went wrong'));और फिर बाद की कॉल fs.readFileत्रुटि को वापस कर देगी जब तक आप स्टब के माध्यम से वापस नहीं आते हैं readFileStub.restore()। व्यक्तिगत रूप से मुझे संदेहास्पद उपयोग का DI मिल गया है क्योंकि मुझे ऐसा लगता है कि इसके लिए लगभग कक्षाओं / वस्तुओं के उपयोग की आवश्यकता होती है, जो कि जावास्क्रिप्ट के कार्यात्मक झुकाव को देखते हुए एक संदिग्ध धारणा है।
केविन

इस अच्छे + विस्तृत उत्तर के लिए धन्यवाद। मैंने लगभग इसे याद किया, जैसा कि मैंने पहली बार C # में हेडलाइन DI को पढ़ा था ।
कॉन्स्टेंटिन ए। मैग

1
बहुत बढ़िया जवाब। मैं सोच रहा हूँ क्या अपने विचारों, व्यक्तिगत पसंद की बात के रूप में, 2019 में हैं बड़ी परियोजनाओं के लिए जो आप करना चाहते हैं - डि / आईओसी नोड में, या बस छोटा करते / साथ मजाक jest, rewire, proxyquire, आदि? धन्यवाद।
जेमी कॉर्कहिल

शानदार संतुलित जवाब! धन्यवाद।
जॉनी ओशिका

36

मैंने इसे पूरा करने के लिए एक मॉड्यूल भी लिखा है, इसे rewire कहा जाता है । बस उपयोग करें npm install rewireऔर फिर:

var rewire = require("rewire"),
    myModule = rewire("./path/to/myModule.js"); // exactly like require()

// Your module will now export a special setter and getter for private variables.
myModule.__set__("myPrivateVar", 123);
myModule.__get__("myPrivateVar"); // = 123


// This allows you to mock almost everything within the module e.g. the fs-module.
// Just pass the variable name as first parameter and your mock as second.
myModule.__set__("fs", {
    readFile: function (path, encoding, cb) {
        cb(null, "Success!");
    }
});
myModule.readSomethingFromFileSystem(function (err, data) {
    console.log(data); // = Success!
});

मैं नाथन मैकइन्स के इंजेक्टर से प्रेरित रहा हूं, लेकिन एक अलग दृष्टिकोण का इस्तेमाल किया। मैं vmपरीक्षण-मॉड्यूल को विकसित करने के लिए उपयोग नहीं करता , वास्तव में मैं नोड की अपनी आवश्यकता का उपयोग करता हूं। इस तरह आपका मॉड्यूल बिल्कुल उपयोग करता है require()(अपने संशोधनों को छोड़कर)। इसके अलावा डिबगिंग पूरी तरह से समर्थित है।


7
2014 के मध्य तक - npmjs.org/package/proxyquire मॉकिंग करता है जिससे "निर्भरता" की आवश्यकता होती है।
आर्केल्डन

प्रॉक्सी भी शांत है! वे अब आंतरिक "मॉड्यूल" -मॉड्यूल का उपयोग कर रहे हैं जो नोड के वीएम का उपयोग करने से बेहतर है। लेकिन आखिरकार यह सिर्फ स्टाइल की बात है। मुझे मूल आवश्यकता का उपयोग करने के लिए और बाद में निर्भरताओं की अदला-बदली करने के लिए मेरा मॉड्यूल पसंद है। इसके अलावा rewire भी ग्लोबल्स को ओवरराइड करने की अनुमति देता है।
जोहान्स एलावड

बहुत दिलचस्प काम पर उपयोग करने के लिए कुछ इस तरह की तलाश में था, क्या यह मॉड्यूल डाउनस्ट्रीम मॉड्यूल को भी प्रभावित करता है?
अक्स्ट

के लिए proxyquire यह वर्णन है कि यह परीक्षण के लिए प्रयोग किया जाता है में कहा गया है, 'प्रॉक्सी NodeJS क्रम दौरान निर्भरता ओवरराइड करने के लिए आवश्यकता होती है में परीक्षण ।' DI के लिए नहीं, है ना?
मार्वेन ट्रैबेल्सि

17

मैंने इस उद्देश्य के लिए इलेक्ट्रोलाइट का निर्माण किया । अन्य निर्भरता इंजेक्शन समाधान मेरे स्वाद के लिए बहुत आक्रामक थे, और वैश्विक के साथ खिलवाड़ कर रहे थेrequire एक विशेष शिकायत है।

इलेक्ट्रोलाइट मॉड्यूल को गले लगाते हैं, विशेष रूप से वे जो "सेटअप" फ़ंक्शन को निर्यात करते हैं जैसे आप कनेक्ट / एक्सप्रेस मिडलवेयर में देखते हैं। अनिवार्य रूप से, इन प्रकार के मॉड्यूल केवल किसी वस्तु के लिए कारखाने हैं जो वे वापस लौटते हैं।

उदाहरण के लिए, डेटाबेस कनेक्शन बनाने वाला मॉड्यूल:

var mysql = require('mysql');

exports = module.exports = function(settings) {
  var connection = mysql.createConnection({
    host: settings.dbHost,
    port: settings.dbPort
  });

  connection.connect(function(err) {
    if (err) { throw err; }
  });

  return connection;
}

exports['@singleton'] = true;
exports['@require'] = [ 'settings' ];

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

डेटाबेस कनेक्शन बनाने के लिए:

var db = electrolyte.create('database');

इलेक्ट्रोलाइट ट्रांसीवरली ट्रैवर्सेज़ @require 'डी निर्भरता का पता लगाता है, और निर्यात फ़ंक्शन के तर्क के रूप में इंस्टेंस को इंजेक्ट करता है।

कुंजी यह है कि यह न्यूनतम इनवेसिव है। यह मॉड्यूल पूरी तरह से प्रयोग करने योग्य है, इलेक्ट्रोलाइट से स्वतंत्र है। इसका मतलब है कि आपकी इकाई परीक्षण परीक्षण के तहत सिर्फ मॉड्यूल का परीक्षण कर सकती है , आंतरिक पुनरावृत्ति के लिए अतिरिक्त निर्भरता की आवश्यकता के बिना नकली वस्तुओं में गुजर रहे हैं।

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


1
क्या आप स्पष्ट करेंगे कि जब कॉल connect()फेंकता है तो आपके द्वारा पोस्ट किए गए कोड में क्या होता है? यद्यपि मैं नोड के लिए MySql API से परिचित नहीं हूं, फिर भी मैं इस कॉल को अतुल्यकालिक होने की उम्मीद करूंगा, इसलिए चित्रण बिल्कुल स्पष्ट नहीं है।
एंड्रे अगिबालोव

वर्तमान में इलेक्ट्रोलाइट का उपयोग कर। आप दावा करते हैं कि निर्यात ['@ आवश्यकता'] के माध्यम से मॉड्यूल को जोड़ना आसान है। लेकिन अगर मुझे आवश्यक मॉड्यूल में से एक को स्टुब करना है तो इलेक्ट्रोलाइट में यह कैसे संभव है। वर्तमान में अगर हमें मॉड्यूल की आवश्यकता होती है तो इसे आसानी से प्राप्त किया जा सकता है। लेकिन इलेक्ट्रोलाइट के लिए यह एक बड़ा नकारात्मक है .... क्या आपके पास ऐसे उदाहरण हैं जहां हम मॉड्यूल के स्टब्ड संस्करण का उपयोग कर सकते हैं और इसे गतिशील रूप से पास कर सकते हैं जबकि परीक्षण के मामलों से तत्काल / ioc.use। मूल रूप से यूनिट टेस्ट में, अगर हम ioc.create ('modulename') कर सकते हैं और फिर डिपेंडेंट मॉड्यूल्स के इंजेक्शन (लेकिन स्टड वाले) आदर्श होंगे ...
user1102171

1
आप ioc.createएक इकाई परीक्षण से फोन नहीं करेंगे । एक इकाई परीक्षण में केवल परीक्षण के तहत मॉड्यूल का परीक्षण करना चाहिए , और इलेक्ट्रोलाइट सहित अन्य निर्भरता में नहीं लाना चाहिए। इस सलाह के बाद, आप करेंगेobjToTest = require('modulename')(mockObj1, mockObj2);
जारेड हैनसन

8

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

मैं मानकों के लिए ईएस 6 सुविधाओं का व्यापक उपयोग करता हूं और कुछ बॉयलरप्लेट से बचने के लिए और एक नामित निर्भरता ओवरराइड तंत्र प्रदान करने के लिए विनाशकारी है।

यहाँ एक उदाहरण है:

import foo from './utils/foo';
import bob from './utils/bob';

// We export a factory which accepts our dependencies.
export const factory = (dependencies = {}) => {
  const {
    // The 'bob' dependency.  We default to the standard 'bob' imp if not provided.
    $bob = bob, 
    // Instead of exposing the whole 'foo' api, we only provide a mechanism
    // with which to override the specific part of foo we care about.
    $doSomething = foo.doSomething // defaults to standard imp if none provided.
  } = dependencies;  

  return function bar() {
    return $bob($doSomething());
  }
}

// The default implementation, which would end up using default deps.
export default factory();

और यहाँ इसका उपयोग का एक उदाहरण है

import { factory } from './bar';

const underTest = factory({ $bob: () => 'BOB!' }); // only override bob!
const result = underTest();

इसके साथ अपरिचित लोगों के लिए ES6 सिंटैक्स का उपयोग करें।


वास्तव में बहुत सरल!
अर्नोल्ड

4

मैंने हाल ही में इस धागे को ओपी के रूप में एक ही कारण के लिए जाँच किया है - मैंने जिन अधिकांश परिवादों का सामना किया है, वे अस्थायी रूप से आवश्यकता विवरण को फिर से लिखते हैं। मैंने इस पद्धति के साथ सफलता की डिग्री को मिलाया है, और इसलिए मैंने निम्नलिखित दृष्टिकोण का उपयोग करके समाप्त किया।

एक एक्सप्रेस आवेदन के संदर्भ में - मैं एक bootstrap.js फ़ाइल में app.js लपेटता हूं:

var path = require('path');
var myapp = require('./app.js');

var loader = require('./server/services/loader.js');

// give the loader the root directory
// and an object mapping module names 
// to paths relative to that root
loader.init(path.normalize(__dirname), require('./server/config/loader.js')); 

myapp.start();

लोडर को दिया गया ऑब्जेक्ट मैप इस तरह दिखता है:

// live loader config
module.exports = {
    'dataBaseService': '/lib/dataBaseService.js'
}

// test loader config
module.exports = {
    'dataBaseService': '/mocks/dataBaseService.js'
    'otherService' : {other: 'service'} // takes objects too...
};

फिर, सीधे कॉल करने की बजाय आवश्यकता होती है ...

var myDatabaseService = loader.load('dataBaseService');

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

मैंने अभी सुविधा के लिए थोड़ा npm मॉड्यूल प्रकाशित किया है:

https://npmjs.org/package/nodejs-simple-loader


3

वास्तविकता यह है कि आप IoC कंटेनर के बिना अपने नोड.जेएस का परीक्षण कर सकते हैं क्योंकि जावास्क्रिप्ट वास्तव में गतिशील प्रोग्रामिंग भाषा है और आप रन-टाइम पर लगभग सब कुछ संशोधित कर सकते हैं।

निम्नलिखित को धयान मे रखते हुए:

import UserRepository from "./dal/user_repository";

class UserController {
    constructor() {
        this._repository = new UserRepository();
    }
    getUsers() {
        this._repository.getAll();
    }
}

export default UserController;

तो आप रन-टाइम पर घटकों के बीच युग्मन को ओवरराइड कर सकते हैं। मुझे लगता है कि हमें अपने जावास्क्रिप्ट मॉड्यूल को खत्म करने का लक्ष्य रखना चाहिए।

वास्तविक डिकम्पलिंग को प्राप्त करने का एकमात्र तरीका संदर्भ को हटाकर है UserRepository:

class UserController {
    constructor(userRepository) {
        this._repository = userRepository;
    }
    getUsers() {
        this._repository.getAll();
    }
}

export default UserController;

इसका मतलब है कि कहीं और आपको ऑब्जेक्ट कंपोजीशन करने की आवश्यकता होगी:

import UserRepository from "./dal/user_repository";
import UserController from "./dal/user_controller";

export default new UserController(new UserRepository());

मुझे एक आईओसी कंटेनर में ऑब्जेक्ट रचना को सौंपने का विचार पसंद है। आप लेख में इस विचार के बारे में अधिक जान सकते हैं जावास्क्रिप्ट में निर्भरता के वर्तमान स्थिति । लेख कुछ "जावास्क्रिप्ट IoC कंटेनर मिथकों" को समाप्त करने की कोशिश करता है:

मिथक 1: जावास्क्रिप्ट में IoC कंटेनरों के लिए कोई जगह नहीं है

मिथक 2: हमें IoC कंटेनरों की आवश्यकता नहीं है, हमारे पास पहले से ही मॉड्यूल लोडर हैं!

मिथक 3: निर्भरता का उलटा === निर्भरता का इंजेक्शन

यदि आप भी एक IoC कंटेनर का उपयोग करने का विचार पसंद करते हैं तो आप InversifyJS पर एक नज़र डाल सकते हैं। नवीनतम रिलीज़ (2.0.0) कई उपयोग मामलों का समर्थन करती है:

  • कर्नेल मॉड्यूल
  • कर्नेल मिडलवेयर
  • निर्भरता पहचानकर्ता के रूप में कक्षाओं, स्ट्रिंग शाब्दिक या प्रतीकों का उपयोग करें
  • निरंतर मूल्यों का इंजेक्शन
  • क्लास कंस्ट्रक्टर का इंजेक्शन
  • कारखानों का इंजेक्शन
  • ऑटो का कारखाना
  • प्रदाताओं का इंजेक्शन (एसिंक्स फैक्ट्री)
  • सक्रियकरण हैंडलर (प्रॉक्सी को इंजेक्ट करने के लिए उपयोग किया जाता है)
  • बहु इंजेक्शन
  • टैग की गईं बाइंडिंग
  • कस्टम टैग डेकोरेटर्स
  • जिसे बाइंडिंग नाम दिया गया है
  • प्रासंगिक बाइंडिंग
  • अनुकूल अपवाद (जैसे परिपत्र निर्भरता)

आप इसके बारे में InversifyJS पर अधिक जान सकते हैं ।


2

ईएस 6 के लिए मैंने इस कंटेनर को विकसित किया https://github.com/zazoomauro/node-d dependency-injection

import {ContainerBuilder} from 'node-dependency-injection'

let container = new ContainerBuilder()
container.register('mailer', 'Mailer')

फिर आप सेट कर सकते हैं, उदाहरण के लिए, कंटेनर में परिवहन का विकल्प:

import {ContainerBuilder} from 'node-dependency-injection'

let container = new ContainerBuilder()
container
  .register('mailer', 'Mailer')
  .addArgument('sendmail')

यह वर्ग अब और अधिक लचीला है क्योंकि आपने कार्यान्वयन से बाहर और कंटेनर में परिवहन की पसंद को अलग कर दिया है।

अब जब मेलर सेवा कंटेनर में है तो आप इसे अन्य वर्गों की निर्भरता के रूप में इंजेक्ट कर सकते हैं। यदि आपके पास न्यूज़लैटरमैन क्लास इस तरह है:

class NewsletterManager {
    construct (mailer, fs) {
        this._mailer = mailer
        this._fs = fs
    }
}

export default NewsletterManager

जब न्यूज़लेटर_मनगर सेवा को परिभाषित करते हैं, तो मेलर सेवा अभी तक मौजूद नहीं है। मेलर सेवा को इंजेक्ट करने के लिए कंटेनर को बताने के लिए संदर्भ वर्ग का उपयोग करें जब यह समाचार पत्र प्रबंधक को प्रारंभ करता है:

import {ContainerBuilder, Reference, PackageReference} from 'node-dependency-injection'
import Mailer from './Mailer'
import NewsletterManager from './NewsletterManager'

let container = new ContainerBuilder()

container
  .register('mailer', Mailer)
  .addArgument('sendmail')

container
  .register('newsletter_manager', NewsletterManager)
  .addArgument(new Reference('mailer'))
  .addArgument(new PackageReference('fs-extra'))

आप कंटेनर को कॉन्फ़िगरेशन फ़ाइलों जैसे यमल, जसन या जेएस फ़ाइलों के साथ भी सेट कर सकते हैं

सर्विस कंटेनर को विभिन्न कारणों से संकलित किया जा सकता है। इन कारणों में किसी भी संभावित मुद्दों जैसे परिपत्र संदर्भ और कंटेनर को अधिक कुशल बनाना शामिल है।

container.compile()

1

यह आपके एप्लिकेशन के डिज़ाइन पर निर्भर करता है। आप स्पष्ट रूप से एक जावा जैसे इंजेक्शन कर सकते हैं जहां आप इस तरह के कंस्ट्रक्टर में पारित निर्भरता के साथ एक वर्ग की वस्तु बनाते हैं।

function Cache(store) {
   this._store = store;
}

var cache = new Cache(mysqlStore);

यदि आप जावास्क्रिप्ट में OOP नहीं कर रहे हैं, तो आप एक init फ़ंक्शन कर सकते हैं जो सब कुछ सेट करता है।

हालाँकि, एक और दृष्टिकोण है जिसे आप ले सकते हैं जो कि ईवेंट आधारित प्रणाली जैसे नोड.जेएस में अधिक सामान्य है। यदि आप आपको केवल (अधिकतर समय) घटनाओं के लिए आवेदन करने के लिए मॉडल कर सकते हैं, तो आपको बस इतना करना है कि सब कुछ सेट करना है (जो मैं आमतौर पर एक इनिट फ़ंक्शन को कॉल करके करता हूं) और एक ठूंठ से घटनाओं का उत्सर्जन करता हूं। यह परीक्षण को काफी आसान और पठनीय बनाता है।


आपके उत्तर के लिए धन्यवाद, लेकिन मैं आपके उत्तर के दूसरे भाग को पूरी तरह से नहीं समझता।
एरिक

1

मुझे हमेशा IoC अवधारणा की सादगी पसंद आई - "आपको पर्यावरण के बारे में कुछ भी जानने की जरूरत नहीं है, आपको जरूरत पड़ने पर किसी के द्वारा बुलाया जाएगा"

लेकिन मैंने देखा कि सभी आईओसी कार्यान्वयन बिल्कुल विपरीत थे - वे कोड को इसके बिना भी अधिक चीजों के साथ अव्यवस्थित करते हैं। इसलिए, मैंने अपना खुद का IoC बनाया है जो काम करता है जैसा मैं चाहता हूं - यह 90% समय छिपा हुआ और अदृश्य रहता है

इसका उपयोग मोनोजेएस वेब फ्रेमवर्क http://monojs.org में किया जाता है

मैं साधारण चीजों के बारे में बात कर रहा हूं, जैसे कि डेटाबेस कनेक्शन ऑब्जेक्ट साझा करना, अब तक, लेकिन मुझे ऐसा समाधान नहीं मिला है जो मुझे संतुष्ट करता हो।

यह इस तरह किया जाता है - रजिस्टर घटक एक बार विन्यास में।

app.register 'db', -> 
  require('mongodb').connect config.dbPath

और इसे कहीं भी इस्तेमाल करें

app.db.findSomething()

आप पूर्ण घटक परिभाषा कोड (DB कनेक्शन और अन्य घटकों के साथ) यहाँ देख सकते हैं https://github.com/sinizinairina/mono/blob/master/mono.cfi

यह एकमात्र स्थान है जब आपको आईओसी को बताना है कि क्या करना है, इसके बाद उन सभी घटकों को स्वचालित रूप से बनाया और वायर्ड किया जाएगा और आपको अब अपने आवेदन में आईओसी विशिष्ट कोड देखने की आवश्यकता नहीं है।

आईओसी ही https://github.com/alexeypetrushin/miconjs


6
हालांकि एक DI के रूप में विज्ञापित, यह एक सेवा लोकेटर की तरह अधिक लगता है।
KyorCode

2
बहुत अच्छा लग रहा है, यह केवल छायांकन में शर्म की बात है
राफेल पी। मिरांडा

1

मुझे लगता है कि हमें अभी भी Nodejs में निर्भरता इंजेक्शन की आवश्यकता है क्योंकि यह सेवाओं के बीच निर्भरता को कम करता है और अनुप्रयोग को स्पष्ट करता है।

स्प्रिंग फ्रेमवर्क से प्रेरित होकर , मैं नोडोड्स में निर्भरता इंजेक्शन का समर्थन करने के लिए अपने स्वयं के मॉड्यूल को भी लागू करता हूं। मेरा मॉड्यूल आपके एप्लिकेशन को पुनरारंभ किए बिना भी code changesऔर auto reloadसेवाओं का पता लगाने में सक्षम है ।

मेरे प्रोजेक्ट पर जाएँ: बनी - IoC कंटेनर

धन्यवाद!



0

मैंने लंबे समय तक .Net, PHP और Java के साथ काम किया इसलिए मैं NodeJS में भी एक सुविधाजनक डिपेंडेंसी इंजेक्शन चाहता था। लोगों ने कहा NodeJS में अंतर्निहित DI पर्याप्त है क्योंकि हम इसे मॉड्यूल के साथ प्राप्त कर सकते हैं। लेकिन इसने मुझे अच्छी तरह से संतुष्ट नहीं किया। मैं एक मॉड्यूल को एक वर्ग से अधिक नहीं रखना चाहता था। इसके अतिरिक्त, मैं चाहता था कि DI को मॉड्यूल जीवन चक्र प्रबंधन (सिंगलटन मॉड्यूल, क्षणिक मॉड्यूल आदि) के लिए पूर्ण समर्थन मिले, लेकिन नोड मॉड्यूल के साथ, मुझे बहुत बार मैनुअल कोड लिखना पड़ता था। अंत में, मैं यूनिट टेस्ट को आसान बनाना चाहता था। इसलिए मैंने अपने लिए एक डिपेंडेंसी इंजेक्शन बनाया।

यदि आप DI की तलाश कर रहे हैं, तो इसे आज़माएं। यह यहाँ पाया जा सकता है: https://github.com/robo-creative/nodejs-robo-container । यह पूरी तरह से प्रलेखित है। यह DI के साथ कुछ सामान्य समस्याओं और उन्हें OOP तरीके से हल करने के तरीके को भी संबोधित करता है। आशा करता हूँ की ये काम करेगा।


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

-1

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

मान लें कि निम्न कोड एक फ़ाइल में है, जिसे कंसोलमेसेपेजप्रिन्टर.जेएस कहा जाता है

'use strict';

// Our console message printer
// deps is injected by circuitbox with the dependencies
function ConsoleMessagePrinter(deps) {
  return {
    print: function () {
      console.log(deps.messageSource.message());
    }
  };
}

module.exports = ConsoleMessagePrinter;

मान लें कि फ़ाइल main.js में निम्न है

'use strict';

// our simple message source
// deps is injected by circuitbox with the dependencies
var simpleMessageSource = function (deps) {
  return {
    message: function () {
      return deps.message;
    }
  };
};

// require circuitbox
var circuitbox = require('../lib');

// create a circuitbox
circuitbox.create({
  modules: [
    function (registry) {
      // the message to be used
      registry.for('message').use('This is the message');

      // define the message source
      registry.for('messageSource').use(simpleMessageSource)
        .dependsOn('message');

      // define the message printer - does a module.require internally
      registry.for('messagePrinter').requires('./consoleMessagePrinter')
        .dependsOn('messageSource');
    }
  ]
}).done(function (cbx) {

  // get the message printer and print a message
  cbx.get('messagePrinter').done(function (printer) {
    printer.print();
  }, function (err) {
    console.log('Could not recieve a printer');
    return;
  });

}, function (err) {
  console.log('Could not create circuitbox');
});

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

प्रोजेक्ट अल्फा वर्जन में है। आपकी टिप्पणियों, विचारों और प्रतिक्रिया का स्वागत है।

आशा करता हूँ की ये काम करेगा!


-1

मुझे लगता है कि अन्य पदों ने डि का उपयोग करने के तर्क में बहुत अच्छा काम किया है। मेरे लिए कारण हैं

  1. उनके रास्तों को जाने बिना निर्भरता को इंजेक्ट करें। इसका मतलब है कि यदि आप डिस्क पर एक मॉड्यूल स्थान बदलते हैं या इसे दूसरे के साथ स्वैप करते हैं, तो आपको उस पर निर्भर होने वाली प्रत्येक फ़ाइल को छूने की आवश्यकता नहीं है।

  2. यह requireबिना किसी समस्या के काम करने वाले वैश्विक कार्य को ओवरराइड करने की पीड़ा के बिना परीक्षण के लिए निर्भरता का मज़ाक बनाना बहुत आसान बनाता है।

  3. यह मदद करता है कि आप के बारे में व्यवस्थित और शिथिल युग्मित मॉड्यूल के रूप में आवेदन करें।

लेकिन मेरे पास एक डीआई फ्रेमवर्क खोजने में बहुत कठिन समय था जिसे मैं और मेरी टीम आसानी से अपना सकते हैं। इसलिए मैंने हाल ही में इन विशेषताओं के आधार पर डेपी नामक एक ढांचा बनाया है

  • मिनिमल एपीआई जिसे कुछ ही मिनटों में सीखा जा सकता है
  • कोई अतिरिक्त कोड / कॉन्फ़िगरेशन / एनोटेशन की आवश्यकता नहीं है
  • requireमॉड्यूल के लिए एक से एक प्रत्यक्ष मानचित्रण
  • मौजूदा कोड के साथ काम करने के लिए आंशिक रूप से अपनाया जा सकता है

-1

यह इस तरह लचीला और सरल होना चाहिए:

var MyClass1 = function () {}
var MyClass2 = function (myService1) {
    // myService1.should.be.instanceof(MyClass1); 
}


container.register('myService1', MyClass1);
container.register('myService2', MyClass2, ['myService1']);

मैंने नोड.जे में डिपेंडेंसी इंजेक्शन के बारे में लेख लिखा है

मुझे उम्मीद है कि इससे आपको मदद मिल सकती है।


-1

Node.js को किसी अन्य प्लेटफ़ॉर्म के रूप में DI की आवश्यकता होती है। यदि आप कुछ बड़ा निर्माण कर रहे हैं, तो DI आपके कोड की निर्भरता का मज़ाक बनाना और आपके कोड का पूरी तरह से परीक्षण करना आसान बना देगा।

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

मॉड्यूल मापदंडों के रूप में निर्भरता को पारित करने के लिए एक समाधान होगा:

module.exports = function (dep1, dep2) {
// private methods

   return {
    // public methods
       test: function(){...}
   }
}

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

वहाँ अन्य समाधान हैं (ब्रॉडवे, आर्किटेक्ट आदि) जो आपको इसमें मदद कर सकते हैं। हालाँकि वे जितना चाहते हैं उससे अधिक कर सकते हैं या अधिक अव्यवस्था का उपयोग कर सकते हैं।


लगभग प्राकृतिक विकास के माध्यम से मैंने ऐसा ही किया है। मैं एक पैरामीटर के रूप में एक निर्भरता से गुजरता हूं और यह परीक्षण के लिए बहुत अच्छा काम करता है।
8

-1

मैंने एक पुस्तकालय विकसित किया है जो निर्भरता इंजेक्शन को एक सरल तरीके से संभालता है, जो बॉयलरप्लेट कोड को कम करता है। प्रत्येक मॉड्यूल को एक अद्वितीय नाम और एक नियंत्रक फ़ंक्शन द्वारा परिभाषित किया गया है। नियंत्रक के पैरामीटर मॉड्यूल की निर्भरता को दर्शाते हैं।

KlarkJS पर अधिक पढ़ें

संक्षिप्त उदाहरण:

KlarkModule(module, 'myModuleName1', function($nodeModule1, myModuleName2) {
    return {
        log: function() { console.log('Hello from module myModuleName1') }
    };
});
  • myModuleName1 मॉड्यूल का नाम है।
  • $nodeModule1से एक बाहरी पुस्तकालय है node_module। नाम से हल होता है node-module1। उपसर्ग $इंगित करता है कि यह एक बाहरी मॉड्यूल है।
  • myModuleName2 एक आंतरिक मॉड्यूल का नाम है।
  • नियंत्रक के रिटर्न मूल्य का उपयोग अन्य आंतरिक मॉड्यूल से किया जाता है, जब वे पैरामीटर को परिभाषित करते हैं myModuleName1

-1

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

उत्तर स्पष्ट रूप से इस धागे में दिए गए लोगों के लिए रुझान था: यह निर्भर करता है। दोनों दृष्टिकोणों के लिए ट्रेड-ऑफ हैं और इस प्रश्न के उत्तर को पढ़ना उनके लिए एक अच्छा आकार देता है।

तो, इस सवाल का असली जवाब यह होना चाहिए कि कुछ स्थितियों में, आप एक डीआई प्रणाली का उपयोग करेंगे, दूसरों में नहीं।

कहा कि, एक डेवलपर के रूप में आप जो चाहते हैं, वह खुद को दोहराना नहीं है और अपने विभिन्न अनुप्रयोगों में अपनी सेवाओं का पुन: उपयोग करना है।

इसका मतलब यह है कि हमें उन सेवाओं को लिखना चाहिए जो डीआई सिस्टम में उपयोग करने के लिए तैयार हैं लेकिन डीआई पुस्तकालयों से बंधे नहीं हैं। मेरे लिए, इसका मतलब है कि हमें इस तरह की सेवाएं लिखनी चाहिए:

module.exports = initDBService;

// Tells any DI lib what it expects to find in it context object
// The $inject prop is the de facto standard for DI imo 
initDBService.$inject = ['ENV'];

// Note the context object, imo, a DI tool should bring
// services in a single context object
function initDBService({ ENV }) {
/// actual service code
}

इस तरह से आपकी सेवा काम नहीं करती है अगर आप इसका उपयोग डीआई उपकरण के साथ या बिना करते हैं।


-1

टाइपडीआई यहां बताई गई सबसे प्यारी है, टाइपडीआई में इस कोड को देखें

import "reflect-metadata";
import {Service, Container} from "typedi";

@Service()
class SomeClass {

    someMethod() {
    }

}

let someClass = Container.get(SomeClass);
someClass.someMethod();

इस कोड को भी देखें:

import {Container, Service, Inject} from "typedi";

// somewhere in your global app parameters
Container.set("authorization-token", "RVT9rVjSVN");

@Service()
class UserRepository {

    @Inject("authorization-token")
    authorizationToken: string;

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