Подтвердить что ты не робот

Управление зависимостями JavaScript

В настоящее время я поддерживаю большое количество JS файлов, и проблема зависимости растет над моей головой. Прямо сейчас у меня есть каждая функция в отдельном файле, и я вручную поддерживаю базу данных для разработки зависимостей между функциями.

Это я хотел бы автоматизировать. Например, если у меня есть функция f

Array.prototype.f = function() {};

на который ссылается другая функция g

MyObject.g = function() {
    var a = new Array();
    a.f();
};

Я хочу иметь возможность обнаружить, что g ссылается на f.

Как мне это сделать? С чего начать? Нужно ли мне писать компилятор или я могу, например, настроить Spidermonkey? Кто-нибудь еще это сделал?

Любые указатели, чтобы начать меня, очень ценится

Спасибо Dok

4b9b3361

Ответ 1

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

JavaScript - это динамически типизированный язык, поэтому нет никакого практического способа узнать, что a, если он передан из функции g, является Array, и поэтому, если f() вызывается там есть зависимость. Определяется только, какие переменные содержат типы во время выполнения, поэтому, чтобы узнать, что вам нужен интерпретатор, и вы сделали себе проблему с Тьюрингом.

Не говоря уже о других динамических аспектах JavaScript, которые полностью игнорируют статический анализ, например, выбор свойств по квадратным обозначениям, страшным eval или строкам в тайм-аутах или атрибутах обработчика событий.

Я думаю, что это немного не стартер. Вероятно, вы, вероятно, лучше отслеживаете зависимости вручную, но упрощаете его, группируя связанные функции в модули, которые станут вашей основной единицей отслеживания зависимостей. Хорошо, вы потянете еще несколько функций, которые вам технически нужны, но, надеюсь, не слишком много.

Также полезно проецировать пространство на каждый модуль, поэтому он очень четко определяет, где происходит каждый вызов, что упрощает управление зависимостями вручную (например, с помощью комментария // uses: ThisModule, ThatModule вверху).

Так как расширения встроенных прототипов сложнее отслеживать, держите их до минимума. Расширение, например. Array, чтобы включить методы ECMAScript Fifth Edition (например, indexOf) в браузерах, которые еще не имеют их, это хорошая вещь, чтобы сделать это как базовое исправление, которое будут использовать все сценарии. Добавление полностью новых произвольных функций к существующим прототипам вызывает сомнения.

Ответ 2

Пробовали ли вы использовать диспетчер зависимостей, например RequireJS или LabJS? Я заметил, что в этой теме никто не упоминал.

Из http://requirejs.org/docs/start.html:

Внутри main.js вы можете использовать require() для загрузки любых других скриптов, которые вы необходимо запустить:

require(["helper/util"], function(util) {
    //This function is called when scripts/helper/util.js is loaded.
    //If util.js calls define(), then this function is not fired until
    //util dependencies have loaded, and the util argument will hold
    //the module value for "helper/util".
});

Вы можете также вложить эти зависимости, поэтому helper/util может потребовать некоторые другие файлы внутри себя.

Ответ 3

Как уже было сказано, делать статический анализ в программе JavaScript - это почти невозможная проблема для взлома. Google Closure компилятор делает это в некоторой степени, но затем он также полагается на внешнюю помощь от JSDoc.

У меня была похожая проблема поиска порядка, в котором JS файлы должны быть объединены в предыдущем проекте, а так как было загружено множество JS файлов, вручную обновляя порядок включения казался слишком утомительным. Вместо этого я придерживался определенных соглашений о том, что составляет зависимость для моих целей, и на основе этого и с использованием простого regexp:) я смог создать правильный порядок включения.

В решении используется алгоритм топологическая сортировка для генерации зависимостей graph, который затем перечислял файлы в том порядке, в котором они должны быть включены для удовлетворения всех зависимостей. Поскольку каждый файл был в основном псевдоклассом с использованием синтаксиса MooTools, для моей ситуации можно было создать 3 способа зависимости.

  • Когда класс добавляет некоторый другой класс.
  • Когда класс реализует какой-то другой класс.
  • Когда класс создает экземпляр объекта другого класса с использованием ключевого слова new.

Это было простое и, безусловно, сломанное решение для общего использования, но оно хорошо меня обслуживало. Если вы заинтересованы в решении, вы можете увидеть здесь здесь - в Ruby.

Если ваши зависимости более сложны, возможно, вы можете вручную просмотреть зависимости в каждом файле JS с помощью комментариев и некоторого внутреннего синтаксиса, например:

// requires: Array
// requires: view/TabPanel
// requires: view/TabBar

Затем прочитайте каждый JS файл, проанализируйте требуемые комментарии и постройте граф зависимостей, который даст вам требуемый порядок включения.

Ответ 4

Было бы неплохо иметь инструмент, который может автоматически определять эти зависимости для вас и выбирать, как они загружаются. Лучшие решения сегодня немного более грубые. Я создал диспетчер зависимостей для своих конкретных потребностей, которые хочу добавить в список (диспетчер зависимостей Pyramid). Он имеет некоторые ключевые функции, которые решают некоторые уникальные варианты использования.

  • Обрабатывает другие файлы (включая вставку html для просмотров... да, вы можете разделить свои представления во время разработки).
  • Объединяет файлы для вас в javascript, когда вы готовы к выпуску (нет необходимости устанавливать внешние инструменты)
  • Имеет общий тип для всех html-страниц. Вам нужно только обновить один файл, когда зависимость будет добавлена, удалена, переименована и т.д.

Пример кода, чтобы показать, как он работает во время разработки.

Файл: dependencyLoader.js

//Set up file dependencies
Pyramid.newDependency({
    name: 'standard',
    files: [
    'standardResources/jquery.1.6.1.min.js'
    ]
});

Pyramid.newDependency({
name:'lookAndFeel',
files: [
    'styles.css',
    'customStyles.css',
    'applyStyles.js'
    ]
});

Pyramid.newDependency({
name:'main',
files: [
    'createNamespace.js',
    'views/buttonView.view', //contains just html code for a jquery.tmpl template
    'models/person.js',
    'init.js'
    ],
    dependencies: ['standard','lookAndFeel']
});

Файлы HTML

<head>
    <script src="standardResources/pyramid-1.0.1.js"></script>
    <script src="dependencyLoader.js"></script>
    <script type="text/javascript">
        Pyramid.load('main');
    </script>
</head>

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

Ответ 5

JSAnalyse использует статический анализ кода для обнаружения зависимостей между файлами javascript: http://jsanalyse.codeplex.com/

Он также позволяет вам определить разрешенные зависимости и обеспечить его, например, во время сборки. Конечно, он не может обнаружить все зависимости, потому что javascript является динамическим языком интерпретации, который не является безопасным для типов, как уже упоминалось. Но это по крайней мере заставляет вас знать ваш график зависимостей javascript и помогает вам держать его под контролем.

Ответ 6

Я написал инструмент, чтобы сделать что-то вроде этого: http://github.com/damonsmith/js-class-loader

Это наиболее полезно, если у вас есть java webapp, и вы структурируете свой JS-код в стиле java. Если вы это сделаете, он сможет обнаруживать все ваши зависимости кода и связывать их с поддержкой как времени выполнения, так и времени разбора.