Przekazywanie argumentów do wymagania (podczas ładowania modułu)


114

Czy można przekazywać argumenty podczas ładowania modułu za pomocą wymagania?

Mam moduł login.js, który zapewnia funkcjonalność logowania. Wymaga połączenia z bazą danych i chcę, aby to samo połączenie z bazą danych było używane we wszystkich moich modułach. Teraz eksportuję funkcję login.setDatabase (...), która pozwala mi określić połączenie z bazą danych i która działa dobrze. Ale wolałbym przekazać bazę danych i wszelkie inne wymagania podczas ładowania modułu.

var db = ...
var login = require("./login.js")(db);

Jestem całkiem nowy w NodeJS i zwykle programuję używając Javy i Spring Framework, więc tak ... to jest iniekcja konstruktora :) Czy można zrobić coś takiego jak kod, który podałem powyżej?


Poleciłbym również przyjrzeć się odpowiedziom na to pytanie. Jak wskazałem w mojej odpowiedzi, powszechnym idiomem jest przekazanie appobiektu do wymaganych modułów.
David Weldon

Zamiast wykonywać wszystkie te argumenty przekazując db, możesz użyć pojedynczej implementacji i wywołać db.getInstance () w razie potrzeby.
wulfgarpro

Odpowiedzi:


237

Na podstawie twoich komentarzy w tej odpowiedzi robię to, co próbujesz zrobić w ten sposób:

module.exports = function (app, db) {
    var module = {};

    module.auth = function (req, res) {
        // This will be available 'outside'.
        // Authy stuff that can be used outside...
    };

    // Other stuff...
    module.pickle = function(cucumber, herbs, vinegar) {
        // This will be available 'outside'.
        // Pickling stuff...
    };

    function jarThemPickles(pickle, jar) {
        // This will be NOT available 'outside'.
        // Pickling stuff...

        return pickleJar;
    };

    return module;
};

W ten sposób konstruuję prawie wszystkie moje moduły. Wydaje mi się, że działa dobrze dla mnie.


Czy appargument jest konieczny, czy mogę go pominąć? Mój moduł nie będzie jawnie używał tego argumentu aplikacji, ale nie wiem, czy jest to wymagane przez node.js dla jakiejś wewnętrznej rzeczy. Jeśli wszystko jest w porządku, moja deklaracja modułu wyglądałaby następująco:module.exports = function (db) {
Ulysses Alves

Było to specyficzne dla aplikacji Express, więc zdecydowanie nie jest konieczne.
floatingLomas

@floatingLomas Mechanizm serializacji w Pythonie nazywa się pickle: stackoverflow.com/questions/11218477/ ...
SadSeven

1
Więc co się stanie, jeśli kilka razy odwołasz się do modułu? Pierwsza require(mymodule)(myargs)daje moduł do pracy. Jeśli jednak odwołujesz się do niego gdzie indziej z innego modułu? w podstawowym systemie wygląda na to, że jest zaangażowana pamięć podręczna, ale w tym systemie pamięć podręczna zwróciłaby samą metodę generatora przy kolejnych wywołaniach do require(), a jeśli przekazałeś argumenty require()(someargs), dostaniesz z powrotem inny moduł ... może brakuje mi coś
Tom H,

2
@TomH W takim przypadku chcesz go buforować. Aby to zrobić, musisz var module;wyjść poza funkcję export, a gdy tylko wejdziesz do funkcji, zechcesz sprawdzić, czy modulejest już zdefiniowana, a jeśli tak, po prostu ją zwróć (a jeśli nie, zainicjuj). Czy to ma sens?
floatingLomas,

37

Nie jestem pewien, czy to nadal będzie przydatne dla ludzi, ale dzięki ES6 mam sposób, aby to zrobić, który uważam za czysty i przydatny.

class MyClass { 
  constructor ( arg1, arg2, arg3 )
  myFunction1 () {...}
  myFunction2 () {...}
  myFunction3 () {...}
}

module.exports = ( arg1, arg2, arg3 ) => { return new MyClass( arg1,arg2,arg3 ) }

I wtedy otrzymujesz oczekiwane zachowanie.

var MyClass = require('/MyClass.js')( arg1, arg2, arg3 )

32

Tak. W swoim loginmodule po prostu wyeksportuj pojedynczą funkcję, która przyjmuje dbargument jako argument. Na przykład:

module.exports = function(db) {
  ...
};

1
Wypróbowałem to. W login.js module.exports = function(app,db) { ... } module.exports.auth = function(req,res) { ... authentication stuff } Wywołuje funkcję „anonymous” i ustawia zmienne appi db, ale kiedy to robi, moja aplikacja nie znajdzie tej authfunkcji. Co ja robię źle? Jeśli usunę funkcję anonimową, funkcja stanie authsię ponownie dostępna.
Andreas Selenwall

Jak wszystko w javascript, exportsjest obiektem. Możesz przypisać do niego właściwości (wielokrotne eksportowanie) lub możesz przypisać go do wartości. Wygląda na to, że przypisałeś eksporty do funkcji, a następnie przypisałeś auth jako właściwość funkcji, którą przypisałeś do eksportu. Więc musiałbyś zrobić, var auth = require("./login.js").authco może nie być tym, co zamierzałeś. Jeśli chcesz użyć wzorca z oryginalnego pytania, prawdopodobnie najlepiej będzie trzymać się jednej wartości eksportu. Jeśli to nadal nie ma sensu, polecam opublikowanie streszczenia dla mnie.
David Weldon

1
Po ponownym przeczytaniu wydaje się, że możesz przypisać authjako właściwość exportsobiektu, a później w module przypisać exportsfunkcję (w ten sposób nadpisując poprzednie przypisanie). Jeśli odwrócisz kolejność przypisania, powinieneś mieć dostęp do authfunkcji zgodnie z oczekiwaniami. Znowu trudno to stwierdzić bez faktycznego zobaczenia kodu.
David Weldon

1
Bardzo dziękuję za Twoją pomoc. To, czego nie zdawałem sobie sprawy, było dokładnie tym, do czego dążyłeś przy użyciu require ('login'). Auth. Myślałem, że nie ma różnicy w var login = require('login')i var login = require('login')(app), ale jest ogromna różnica, nie ma magii w zwróconej funkcji anonimowej, to po prostu kolejna funkcja / obiekt. Zamiast mieć a module.exports.auth, anomymiczna funkcja zwraca teraz funkcję auth (między innymi), tj return { auth: authFunction, login: loginFunction}. Więc teraz to działa. Dzięki.
Andreas Selenwall
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.