[JS] Хорошо проработанный многоразовый асинхронный поток

Или «Асинхронный + Многоразовый = Прибыль»

Прошло много времени с тех пор, как шумиха вокруг умирающего «ада обратных вызовов» и яркого Promise пришла, чтобы спасти нас из этого ада. теперь у нас есть генераторы (ES6) и await/async (ES7)… ура! еще больше возможностей для выбора.

Действительно ли все эти функции что-то решили? Какое-то время я пробовал использовать промисы/генераторы, но было ясно, что это ничего не решает — просто еще один способ делать что-то. По правде говоря, это не только заставило меня писать больше кода, но и не улучшило моего самочувствия по поводу моего асинхронного кода. это выглядит знакомо?

Изучая свои варианты обработки асинхронного потока, я в конце концов выбрал промисы, потому что казалось, что у них есть некоторый потенциал с их синхронным синтаксисом (return/throw) и их встроенной методологией обработки ошибок. они могут легко поддерживаться в любой версии узла, а также в любом современном браузере, и, что наиболее важно, они легко стирают грань между синхронными и асинхронными действиями.

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

new Promise()
Promise.resolve()
Promise.reject()
promise.then()
promise.catch()
promise.all()
promise.race()

Повторное использование важно… если вы не согласны, вы можете с радостью продолжать писать parseQuery loadUser validateParams и другие из этих постоянно необходимых функций и так далее, пока временной континуум не растворится в пространстве.

Ключом к повторному использованию является определение стандартного способа выполнения действия. хорошим примером этого будет npm. мы все знаем, как это работает…
npm i -S package, а затем require('package').

Стандартный способ ведения дел более мощный, чем 1000 функций

Функция потока

Мой стандартный способ основан на двух типах функций: функциях потока и функциях полезной нагрузки.
Функция потока не выполняет никаких прямых действий, а скорее организует цепочку действий для достижения более крупной цели. Для простоты предположим, что мы пишем API для аутентификации пользователя — это слишком упрощенный пример, но он выполняет свою работу.

Поскольку функции полезной нагрузки должны быть тупыми, нам нужен простой стандартный способ взаимодействия с ними. для этого я буду использовать объект payload, который будет передаваться по всей цепочке.
пример функции потока:

Функция полезной нагрузки

Функция полезной нагрузки — самая глупая из возможных. он должен выполнять очень конкретное действие и ничего более, без побочных эффектов и без отдельных асинхронных операций. функция полезной нагрузки может быть либо синхронной, либо асинхронной, либо и той, и другой! поскольку обещания могут принимать как значение, так и другое обещание, это означает, что вы можете динамически решать, является ли действие синхронным или асинхронным.
>Функция полезной нагрузки должна подчиняться этим трем простым правилам
1. все данные либо потребляются из полезной нагрузки, либо добавляются к ней
2. конечным значением должна быть полезная нагрузка
3. должна иметь встроенные документы

Функции полезной нагрузки — это основные повторно используемые блоки. вот пример:

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

Давайте использовать случай

Давайте создадим базовый индексный файл, который передает запросы в модуль API:

и модуль API со скелетами обработчиков маршрутов:

Теперь давайте попробуем реализовать базовую функцию потока.

Обратите внимание, что я использую некоторые встроенные функции внутри функции потока, позже я объясню, в чем смысл этого делать.
Я также использовал свою первую функцию полезной нагрузки respondFromPayload:

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

это синхронная функция? да… но кого это волнует? обещания обрабатывают синхронизируемые и асинхронные возвращаемые значения одинаково.

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

создать токен сеанса:

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

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

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

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

Если бы этот метод использовался в примере, функция потока стала бы еще короче:

Нижняя линия

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

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

Наконец-то я нашел асинхронный поток, которым я доволен, возможно, вы найдете его подходящим и для вас. поделитесь своими мыслями.