Należy tutaj zrozumieć 3 kluczowe punkty, a następnie wyjaśnię je szczegółowo.
- module.exports to obiekt, a obiekty są przekazywane przez kopię odniesienia w JavaScript.
- wymaganie jest synchronicznym funkcja.
- client.connect jest asynchronicznym funkcja.
Jak sugerowałeś, to kwestia czasu. node.js nie może wiedzieć, że module.exports zmieni się później. To nie jest problem. Skąd miałby o tym wiedzieć?
Kiedy require
uruchamia, znajduje plik, który spełnia jego wymagania na podstawie wprowadzonej ścieżki, odczytuje go i wykonuje oraz buforuje moduł module.exports, aby inne moduły mogły require
ten sam moduł i nie trzeba go ponownie inicjować (co mogłoby zepsuć zakres zmiennych itp.)
client.connect jest asynchronicznym wywołaniem funkcji, więc po jej wykonaniu moduł kończy wykonywanie, a require
call przechowuje kopię referencji module.exports i zwraca ją do users.js. Następnie ustawiasz module.exports = db
, ale jest za późno. Zamieniasz referencję module.exports na referencję do db, ale eksport modułu w węźle require
cache wskazuje na stary obiekt.
Lepiej jest zdefiniować module.exports jako funkcję, która uzyska połączenie, a następnie przekaże je do funkcji zwrotnej w następujący sposób:
var mongodb = require("mongodb");
var client = mongodb.MongoClient;
module.exports = function (callback) {
client.connect('mongodb://host:port/dbname', { auto_reconnect: true },
function(err, db) {
if (err) {
console.log(err);
callback(err);
} else {
// export db as member of exports
callback(err, db);
}
}
)
};
Ostrzeżenie:chociaż wykracza to poza zakres tej odpowiedzi, bądź bardzo ostrożny z powyższym kodem, aby upewnić się, że prawidłowo zamykasz/zwracasz połączenia, w przeciwnym razie wyciekniesz z połączeń.