2012-04-24 6 views
56

Używam oddzielnych plików routera jako modułów głównej aplikacji i aplikacji auth. Nie mogę uzyskać najlepszego sposobu przekazywania zmiennych (klienta db) do routerów. Nie chcę, aby zakodować je lub przekazać ją:Jaki jest najlepszy sposób przekazywania wspólnych zmiennych do oddzielnych modułów w Node.js?

module.exports = function(app, db) { 

Może to najlepszy sposób na wykorzystanie Singleton zarejestrować lub użyć zmiennej globalnej db?

Jakie są Twoje doświadczenia z wzorami projektowymi? Która droga jest najlepsza i dlaczego?

+1

możliwy duplikat http://stackoverflow.com/questions/8931239/how-to-access-variables-declared-in-main-app-js-in-seperate-route-files-in-node/8931366 # 8931366 –

Odpowiedz

99

Znalazłem za pomocą zastrzyku zależności, aby przekazać rzeczy, być najlepszym stylu. Byłoby to rzeczywiście wyglądać jak masz:

// App.js 
module.exports = function App() { 
}; 

// Database.js 
module.exports = function Database(configuration) { 
}; 

// Routes.js 
module.exports = function Routes(app, database) { 
}; 

// server.js: composition root 
var App = require("./App"); 
var Database = require("./Database"); 
var Routes = require("./Routes"); 
var dbConfig = require("./dbconfig.json"); 

var app = new App(); 
var database = new Database(dbConfig); 
var routes = new Routes(app, database); 

// Use routes. 

ten ma szereg zalet:

  • To zmusza do oddzielenia systemu na komponenty z wyraźnych zależności, zamiast ukrywać zależności gdzieś w w środku pliku, w którym nazywają się require("databaseSingleton") lub gorzej, global.database.
  • To sprawia, że ​​testy jednostkowe bardzo proste: jeśli chcę przetestować Routes w izolacji, mogę wstrzyknąć go z fałszywymi app i database params i testu tylko kod sama Routes.
  • Umieszcza wszystkie okablowanie obiekt-wykres w jednym miejscu, a mianowicie w głównym katalogu kompozycji (w tym przypadku jest to server.js, punkt wejścia aplikacji). Daje to jedno miejsce do sprawdzenia, jak wszystko pasuje do siebie w systemie.

Jeden z lepszych wyjaśnień dla tego, że widziałem to an interview with Mark Seeman, autor znakomitej książki Dependency Injection w .NET. Dotyczy to również JavaScript, a szczególnie do Node.js: require jest często używany jako klasyczny lokalizator usług, zamiast tylko systemu modułów.

+0

Próbuję użyć tego przykładu, jednak jak zdefiniować moje trasy w implementacji Routes.js, ponieważ jest on w funkcji Routes? Dzięki! – cpeele00

+0

@ cpeele00 w taki sam sposób, jak w przypadku metod innych klas. – Domenic

+0

Czy korzystając z tej konfiguracji, rozdzielasz swoje trasy w podobny sposób? na przykład Trasy (aplikacja, baza danych) {routes = {social: new SocialRoutes (aplikacja, baza danych), api: new ApiRoutes (aplikacja, baza danych)}; trasy powrotne; } – Stephen

2

Proponuję utworzyć plik ustawień z instancją db oraz z innymi rzeczami, których potrzebujesz używać globalnie, jak "singleton".

Na przykład, mam settings.js z moim klientem Redis DB:

var redis = require('redis'); 
exports.redis = redis.createClient(6379, '127.0.0.1'); 

iw innych wielu modułów I obejmują go:

var settings = require('./settings'); 
setting.redis.<...> 

Wiele czasu włączając go zawsze mam jedną instancję połączenia db.

+0

Jeśli używam następnego kodu: ' var redis = require ('redis'); var client = redis.createClient (6379, '127.0.0.1'); client.auth (redispass); exports.client = klient; ' czy ten moduł ponownie połączy się ponownie, czy nie? – Serg

+2

nie, tylko jedno połączenie. Poszukaj [documentation] (http://nodejs.org/api/modules.html#modules_caching), _wielkie wywołania wymagające ('foo') nie mogą powodować, że kod modułu będzie wykonywany wiele razy_ – akaravashkin

+3

Ryzyko polegania na " wymagają "zachowania singletonowego, ponieważ odzyskasz tylko tę samą instancję, jeśli przejdziesz dokładnie tę samą ścieżkę. Moduły są buforowane na podstawie przekazanej ścieżki, a nie na rozwiązanej ścieżce. Innymi słowy, będzie działać jako singleton, dopóki nie spróbujesz go użyć z podkatalogu. –

0

Jest całkowicie przestarzały, ale można użyć global w skrypcie:

global.foo = new Foo(); 

w innym skrypcie:

foo.bar(); 

Można też wykorzystać już istniejący Constant:

Object.foo = new Foo(); 

A tutaj:

Object.foo.bar(); 
1

Możesz zapisać się cały kod boilerplate okablowania swoje moduły jeśli używasz ramy iniekcji zależność

This answer list kilka z nich. Zbudowałem również model simpler DI framework here.

EDIT: poniżej tworzyć kopię odpowiedzi w przypadku, gdy strona zmienia


require jest sposobem zarządzania zależnościami w node.js i na pewno jest to intuicyjne i skuteczne, ale ma również swoje ograniczenia.

Moja rada to przyjrzeć się niektórym pojemnikom Dependency Injection dostępnym dzisiaj dla Node.js, aby mieć pojęcie o ich zaletach/wadach. Niektóre z nich są:

Wystarczy wymienić tylko kilka.

Teraz prawdziwe pytanie brzmi: co można osiągnąć dzięki pojemnikowi DI Node.js w porównaniu z prostym require?

Plusy:

  • lepiej testowalności: moduły akceptuje ich zależności jako wejście
  • odwrócenie sterowania: zdecydować, jak podłączyć moduły bez dotykania głównego kodu aplikacji.
  • konfigurowalny algorytm do rozwiązywania modułów: zależności mają "wirtualne" identyfikatory, zazwyczaj nie są powiązane z ścieżką w systemie plików.
  • Lepsza rozszerzalność: włączona przez IoC i "wirtualne" identyfikatory.
  • Inne fantazyjne rzeczy możliwe:
    • asynchroniczny inicjalizacji
    • zarządzanie Moduł cyklu
    • Rozszerzalność samego kontenera DI
    • można łatwo wdrożyć wyższe pobory poziomie (np AOP)

Przeciw:

  • Różne od Node.js "doświadczenie": nieużywanie require zdecydowanie wydaje się, że odbiegasz od sposobu myślenia Węzeł.
  • Relacja między zależnością a jej implementacją nie zawsze jest jednoznaczna. Zależność może zostać rozwiązana w czasie wykonywania i pod wpływem różnych parametrów. Kod staje się coraz trudniejsze do zrozumienia i debugowania
  • Dłuższy czas uruchamiania
  • zapadalności (w tej chwili): żaden z obecnych rozwiązań jest naprawdę popularne w tej chwili, więc nie tak wiele tutoriali, bez ekosystemu, a nie bitwę przetestowany.
  • Niektóre pojemniki DI nie będą dobrze współpracować z modułami pakującymi, takimi jak Browserify i Webpack.
Powiązane problemy