Могут ли модули узлов требовать друг друга

У меня есть следующие 3 файла.

user.js требует room.js, а room.js требует user.js.

user.js

var Room = require('./room.js');

var User = function () {};
User.prototype.test = function () {
  return new Room();
};

module.exports = User;

room.js

var User = require('./user.js');

var Room = function () {};
Room.prototype.test = function () {
  return new User();
};

module.exports = Room;

index.js

var User = require('./user.js');
var Room = require('./room.js');

var user = new User();
var room = new Room();

user.test();
room.test();

index.js требует и комнаты, и пользователя.

Вот в чем проблема. Когда я запускаю index.js, я получаю TypeError от «new User()» в room.js. Кажется, что пользователь в room.js скрыт пользователем в index.js.

Я делаю что-то не так? Допускается ли такое требование? Любые идеи? Спасибо.


person Ziyu    schedule 28.04.2014    source источник


Ответы (3)


Узнайте, как это обрабатывается в node.

Вы можете решить свою проблему несколькими способами, например, передав зависимости экземплярам, ​​также известным как Dependency Injection.

// user.js
var User = function (Room) { this.Room = Room; };
User.prototype.test = function () {
  return new this.Room();
};
module.exports = User;

// room.js
var Room = function (User) { this.User = User; };
Room.prototype.test = function () {
  return new this.User();
};
module.exports = Room;

// index.js
var User = require('./user.js');
var Room = require('./room.js');

var user = new User(Room);
var room = new Room(User);

Другой способ - требовать файлы только тогда, когда они вам нужны.

// user.js
var User = function () {};
User.prototype.test = function () {
  var Room = require('./room');
  return new Room();
};
module.exports = User;


// room.js
var Room = function () {};
Room.prototype.test = function () {
  var User = require('./user');
  return new User();
};
module.exports = Room;

// index.js
var User = require('./user.js');
var Room = require('./room.js');

var user = new User();
var room = new Room();

Таким образом, ваш экспорт определяется временем, когда он вам нужен.

Но в целом, если у вас круговые зависимости, вы делаете что-то не так и должны подумать о своей архитектуре. Если User нужно создать нового Rooms, а Room нужно создать нового Users, кажется, что у них обоих слишком много ответственности. Возможно, вам нужен третий компонент, который отвечает за создание и передачу правильных экземпляров Room и User, вместо того, чтобы они создавали их напрямую.

person TheShellfishMeme    schedule 28.04.2014
comment
Отличный ответ. Спасибо. Реструктуризация кажется лучшим способом :) - person Ziyu; 29.04.2014
comment
Второй вариант я бы не рекомендовал. Так как импорт модуля является синхронной задачей. Это может заблокировать основной поток. - person Faizi; 17.09.2020

Я думаю, что есть гораздо лучший способ, как это сделать. Просто переключите экспорт и требуйте так:

user.js

var User = function () {};
module.exports = User;    

User.prototype.test = function () {
    return new Room();
};

var Room = require('./room.js');

room.js

var Room = function () {};
module.exports = Room;    

Room.prototype.test = function () {
  return new User();
};

var User = require('./user.js');

index.js

var User = require('./user.js');
var Room = require('./room.js');

var user = new User();
var room = new Room();

user.test();
room.test();

проверьте эту статью: https://coderwall.com/p/myzvmg/circular-dependencies-in-node-js

person balicekt    schedule 06.09.2015
comment
Ух ты! с момента создания www, это самая гениальная вещь, которую я когда-либо видел, это должен быть правильный ответ, спасибо - person Fareed Alnamrouti; 22.09.2016
comment
Это кажется хорошим ответом, но я провел рефакторинг кода, чтобы перейти от метода конструктора к этому методу, и мне пришлось добавить, казалось бы, бесполезную bind() в какой-то код, который раньше работал. Я не тратил время на то, чтобы выяснить основную причину, но будьте осторожны. Мне нравится этот метод, но это был еще один потерянный час... - person Paul S; 02.05.2017

Разница между:

/* code above */
function a() {};

а также

/* code above */
var a = function () {};

Разве что в первом примере a будет функция уже в code above, а во втором примере нет.

Как только вы поймете, что можете прийти к этому простому решению:

// user.js

module.exports = User;

function User() {};
User.prototype.test = function () {
  var Room = require('./room');
  return new Room();
};

// room.js

module.exports = Room;

function Room() {};
Room.prototype.test = function () {
  var User = require('./user');
  return new User();
};

// index.js

var User = require('./user.js');
var Room = require('./room.js');

var user = new User(Room);
var room = new Room(User);
person Alexander    schedule 26.07.2018