Когда циклическая зависимость становится проблемой?

#javascript #typescript #es6-modules #circular-dependency

#javascript #typescript #es6-модули #циклическая зависимость

Вопрос:

Я попробовал madge приложение TypeScript, над которым я работаю:

 npx madge --circular --extensions ts src/  
  

И получил длинный дамп циклических зависимостей (на самом деле их 61). Однако дело в том, что приложение компилируется и работает нормально. Как это возможно? Существуют ли определенные условия, при которых циклические зависимости превращаются в проблему?

Ответ №1:

Синхронный циклический импорт, как правило, в порядке. Думайте о них как о объявлениях, они на самом деле ничего не выполняют. До тех пор, пока вы не используете импорт немедленно, синхронно. Например, это работает:

A.js:

 import B from 'B.js'

export function A() {
  if (/* some condition that doesn't last forever */) return B()
  else return 0 // of course, you don't want an infinite recursive loop either ;)
}
  

B.js:

 import A from 'A.js'

export function B() {
  if (/* some condition that doesn't last forever */) return A()
  else return 0 // same thing
}
  

Вы можете импортировать A и B в другой файл и вызвать их оба там, все будет в порядке. A и B ссылаются друг на друга, но им не нужно использовать друг друга, пока не будет вызван один из них.

Но если вы используете один из двух экспортов синхронно, в то время как другой еще не экспортирован, это приведет к сбою:

A.js:

 import B from 'B.js'

export const A = B(something)
  

B.js:

 import A from 'A.js'

export function B() {
  return A
}
  

Теперь здесь происходит то, что оценка A (которая должна быть выполнена перед ее экспортом) требует вызова B , а для запуска B требуется, чтобы A уже был определен.

Комментарии:

1. Есть ли способ (в madge или любой другой инструмент) выгружать только синхронные циклические зависимости?

2. Я не знаю. Циклический динамический импорт определенно вызовет ошибку, поэтому вам действительно следует беспокоиться о них, а не о синхронном импорте (последние часто объединяются в один файл в любом случае во время процесса сборки).

3. Я просто избегаю циклических зависимостей во всей их полноте в typescript, используя основной индекс экспорта. Экспортируйте ВСЕ через один корневой индекс и импортируйте ВСЕ из этого корневого индекса. Нулевой относительный или индивидуальный импорт файлов. Вы можете экспортировать папки через дочерние индексы и т. Д. И экспортировать их из основного индекса. Но это дает вам один симпатичный график в madge. Затем полагайтесь на тряску webpack или дерева свертки, чтобы отбросить вещи, которые вы не используете. Если у вас есть конфликтующие имена, просто используйте пространство имен для экспорта, например ‘export * as things from ‘./someIndex»

4. Я не понимаю, как это позволяет избежать циклических зависимостей. Вы просто делаете их косвенными. Вместо «A требует B из B.js» и «B требует A из A.js» у вас будет «A требует B из индекса» и «B требует A из индекса», при этом индекс повторно экспортирует как A, так и B из их соответствующих файлов (возможно, путем перебора дополнительных индексов).