Попробуйте живую демонстрацию здесь!

Читая, как Event Loop работает для JavaScript и Node.js, я наткнулся на прекрасное объяснение цикла событий JavaScript от Филипа Робертса. Он сделал отличный визуализатор под названием Лупа. Однако мне не удалось найти подобный визуализатор, поддерживающий API Node.js, например setImmediate() или process.nextTick().

Так почему бы не построить такой, подумал я.

Общая архитектура

Чтобы не изобретать велосипед, проект основан на наиболее близком мне визуализаторе js-visualizer-9000. Этот проект состоит из двух компонентов: внешнего интерфейса и внутреннего интерфейса. Внешний интерфейс отвечает за отправку code и воспроизведение списка event из внутреннего интерфейса. Интерфейс в значительной степени завершен благодаря работе Диллион. Мы сосредоточимся на внутренней стороне проекта. Ядро приложения - это то, как мы инструментируем выполнение кода.

Ход программы можно увидеть на следующей диаграмме.

После того, как мы получим code от внешнего интерфейса, необходимо выполнить несколько шагов.

  1. Создать нового рабочего с помощью Node.js Worker threads API
  • Это позволяет запускать отправленный code в независимом потоке выполнения, предотвращая сбой сервера вредоносным кодом.

2. Преобразование кода и внедрение Tracer с помощью Babel

  • Мы добавим Tracer в инструментальный вызов функции и предотвратим бесконечный цикл.

3. Запустите преобразованный код, используя vm модуль и async-hooks включен

  • Модуль vm позволяет компилировать и запускать преобразованный код.
  • async-hooks включен для инструментального потока асинхронной функции, подробнее здесь

4. Слушайте трансляцию событий от работника.

5. Сбор и сокращение событий

  • Сократите транслируемые события до единообразного формата, чтобы интерфейс мог их воспроизвести.

Инструменты исполнения кода

Мы используем два инструмента для инструментария выполнения кода:

Функция трассировки

Цель Tracer - транслировать event по мере его появления. Затем event используется интерфейсом для воспроизведения и визуализации потока выполнения.

Чтобы использовать Tracer для трансляции события, нам нужно ввести наш Tracer, чтобы вызвать правильный method в нужном месте.

Итак, как мы можем использовать Tracer для инструментария кода? Ответ на этот вопрос заключается в использовании поддержки плагинов от Babel.

Сначала мы преобразуем code, отправленный из внешнего интерфейса, в абстрактное синтаксическое дерево (AST), а затем пройдемся по AST в поисках marker для внедрения нашего кода. Чтобы понять, как это возможно, прочтите здесь.

Используя написанный настраиваемый плагин babel, code будет преобразован, как показано ниже:

Tracer имеет функцию, которая ограничивает цикл до временного ограничения, установленного TIMEOUT_MILLIS.

Асинхронные хуки

Используя async-hooks, мы можем следить за этапом asynchronous операции, что и составляет основу этого визуализатора. Всего API поддерживает пять hook, а именно:

  1. init
  2. before
  3. after
  4. destroy
  5. promiseResolve

Пример hook, зарегистрированного для promiseResolve, выглядит следующим образом:

Мы транслируем события по мере их возникновения по телефону postEvent()

Подробнее о том, как async-hooks работает, читайте здесь.

Вывод

Мы успешно создали визуализатор для Node.js Event Loop, живую демонстрацию, доступную здесь. Код Frontend и Backend помещается в Github, если вы хотите узнать больше о реализации.

Этот проект стал возможным благодаря предыдущим работам Эндрю Диллон и Филип Робертс.

Полезная ссылка:

Инструментарий Javascript Томом Либером

Цикл событий Node.js, автор Deepal Jayasekara