Свой код на JavaScript

Нода code_javascript исполняет ваш JavaScript как шаг графа. Это последняя дверь: то, для чего нет ноды и что не выражается шаблоном.

Сначала — не пишите код

Умолчание в Flow — нода, а не код, и это не идеология. Нода видна на холсте, её видит валидатор, её конфигурация попадает в журнал запуска, её ошибки разложены по кодам, и следующий человек поймёт граф, не читая программу. Код всего этого лишён: он непрозрачен для всех инструментов платформы и стоит дополнительный кредит за прогон.

ЗадачаЧем делатьГде почитать
Собрать строку из нескольких значенийtemplateШаблоны
Разобрать JSON, достать полеjson_parserШаблоны
Ветвление по условиюif / switchЛогика ветвлений
Пройти по спискуwhile_loop / array-нодыЦиклы
Сложить, посчитать, сравнить числаноды логики и строкНоды: обзор
Запрос к внешнему APIhttp_requestHTTP и веб
Табличные данные, CSV, агрегатыdf_*Датафреймы

Ссылки на разделы из последнего столбца: Шаблоны, Логика ветвлений, Циклы, Ноды: обзор, HTTP и веб, Датафреймы.

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

Что приходит и что нужно вернуть

Вы пишете тело функции, а не файл. Платформа оборачивает его так:

async function call(input, ...дополнительные порты) {
  // ваш код
}
  • input — значение, пришедшее на порт Run. Строка, число, объект — что доставил провод данных.
  • Каждый дополнительный входной порт, добавленный на вкладке входов, становится параметром функции с тем же именем. Имена сортируются по алфавиту, так что порядок предсказуем.
  • То, что вы вернёте, и есть выход ноды: {{ nodes.<id>.output }} — это ровно возвращённое значение. Ничего оборачивать не надо.
  • console.log и соседи попадают в журнал запуска ноды — это штатный способ отладки.
  • get_var("имя") / set_var("имя", значение) читают и пишут переменные, объявленные нодами var в этом же графе. Незнакомое имя — ошибка, а не тихое undefined (Состояние).
Вход
JavaScript-код
Выход
  • Исполнение + данные
Дополнительный входной порт становится вторым параметром функции; возвращённое значение уходит на выход успеха.

Ещё одно, что легко принять за поломку: шаблоны в теле кода не подставляются. {{ secret.KEY }}, написанное внутри кода, останется буквальным текстом. Поле кода намеренно не шаблонное — иначе фигурные скобки JavaScript пришлось бы экранировать, а подставленный секрет попадал бы в журнал. Нужен ключ внутри кода — заведите его во входной порт и передайте туда значение отдельной нодой.

Главное: код исполняется не в платформе

Ваш JavaScript выполняется в отдельном контейнере, у которого нет ничего, кроме среды исполнения.

  1. Платформа заранее считает всю политику безопасности — разрешённые хосты, запрещённые диапазоны адресов, потолки времени и памяти, предел размера кода.
  2. Готовое задание уходит в контейнер-исполнитель. Он не умеет ничего решать: набор разрешений, с которыми запускается ваш код, ему передан, а не выбран им, и посторонние разрешения он отвергает.
  3. Под каждый прогон поднимается свежий процесс. Результат и строки console.* текут обратно потоком.

Что у этого контейнера есть и чего нет:

ЧтоЕсть?
Код платформы, её конфигурациянет
Секреты рабочего пространства, ключи моделейнет
Доступ к базе данных, к очереди, к векторному хранилищунет — он даже не в той сети
Файлы рабочего пространства, вложения чатанет
Права на запись в файловую системунет, файловая система только для чтения
Сеть наружуда, но по политике — см. ниже
Ограничение по памяти и процессорному временида, у контейнера жёсткие лимиты

Зачем так, если код всё равно ваш. Затем, что «ваш код» — это код, который писали вы, а исполняет платформа, где живут данные других клиентов. Достаточно одной ошибки в движке JavaScript, чтобы прогон вышел за пределы песочницы. Если бы он выполнялся внутри рабочего процесса платформы, побег означал бы доступ к базе, к чужим секретам и к чужим файлам. Отдельный контейнер превращает тот же побег в попадание в одноразовую пустую коробку без сети к базе и без единого секрета внутри. Изоляция стоит нам сложности развёртывания, а вам — того, что администратор обязан поднять ещё один сервис; ровно поэтому без него исполнение кода не включается.

Сеть

fetch из кода работает. По умолчанию доступны любые публичные адреса; поле Allowed hosts сужает список до перечисленных имён хостов. Приватные и loopback-адреса заблокированы всегда, независимо от настройки, — та же защита, что у http_request, и по той же причине: код, получивший адрес из сообщения пользователя, не должен превращаться в сканер внутренней сети.

Пределы

Что ограниченоЗначение
Время одного прогона5 секунд по умолчанию, потолок 30
Память128 МБ по умолчанию, потолок 512
Размер кода64 КиБ
Одновременных прогонов на исполнительограничено; при переполнении нода падает, а не встаёт в очередь

Превышение времени — это отдельная ошибка «код не уложился в отведённое время», а не общий сбой: её видно в журнале и по ней понятно, что чинить.

Ошибки и биллинг

Выход ошибки у этой ноды выключен по умолчанию (в отличие от http_request): падение вашего собственного кода — это, как правило, дефект, который надо чинить, а не ожидаемый исход, который надо обрабатывать. Включается он тумблером Выход ошибки в основном списке полей ноды (Ошибки нод).

Сообщение самой песочницы автор запуска видит: это его код и его ошибка. Собеседнику в чате оно не показывается никогда.

Что дальше