Использование ES6 генераторов на примере koa.js

  • Tutorial

Автор: Александр Трищенко, Senior Front-end Developer, DataArt

Содержание:
• Итераторы. Генераторы.
• Использование генераторов (Redux, Koa)
• Зачем нам использовать koa.js
• Будущее. Async Await и koa.js 2.x

Генераторы — новая спецификация, новая возможность, которую мы можем использовать в ECMAScript 6. Статью я начну с рассказа об итераторах, без которых понять генераторы не получится, расскажу непосредственно про спецификацию и о том, что такое генераторы вообще, про их использование в реальных кейсах. Рассмотрим два примера: React + Redux как фронтненд-случай и koa.js в качестве бэкенда. Затем подробнее остановлюсь на koa.js, будущем JavaScript, на асинхронных функциях и koa.js 2.

В статье использованы, в том числе, и заимствованные сниппеты (ссылки на источник приведены в конце), и я сразу прошу прощения, что части кода выложены в виде картинок.



ECMAScript 6 (2015) поддерживается достаточно хорошо, чтобы его использовать. На диаграмме видно, что в принципе все неплохо даже у Microsoft в Edge, большие проблемы наблюдаются только у Internet Explorer (вертикальная ось координат — поддержка функциональности, в %). Приятно удивляет Safari 10, по заявлениям команды WebKit, работает все.

Итераторы


• Теперь все, что можно перебрать, – итерируемый объект (iterable).
• Все, что не перебирается само по себе, — можно заставить с помощью своего Symbol.iterator.


Каждый перебираемый, итерируемый тип данных, каждая итерируемая структура данных, получает итератор и становится iterable. Можно перебрать строку, массив, можно перебрать новые структуры данных, такие как Map и Set — все они должны содержать свой итератор. Теперь мы можем получить доступ непосредственно к самому итератору. Также появилась возможность заставить перебираться неперебираемое, и порой это может быть очень удобно.



Что такое итератор? Как вы можете видеть, существует простейший массив. У простейшего массива есть ключ — символ итератора, по сути, фабрика, которая возвращает итератор. Каждый вызов этой фабрики вернет новый экземпляр итератора, мы можем перебирать их независимо друг от друга. В итоге мы получили переменную, хранящую ссылку на итератор. Далее, с помощью единственного метода next, мы его перебираем. Метод next возвращает нам объект, который содержит два ключа, первый — value — непосредственно значение итератора, второй — состояние итератора — done: false.



Описать итератор мы можем самостоятельно. В принципе, он представляет собой фабрику, обычную функцию. Предположим, что у нас есть функция endlessNumbers, есть индекс и метод next. Объект с единственным методом next, который возвращает итерируемое значение и статус. Этот итератор никогда не дойдет до конца, потому что мы никогда не будем присваивать ключу done значение true.

Применяются итераторы довольно широко, особенно в приложениях, которые реализуют нестандартные подходы к работе с информацией. В свободное время я занимаюсь написанием секвенсора на JavaScript с использованием Web Audio API. У меня есть задача: проигрывать с определенными интервалами какую-то ноту. Укладывать это в какой-то цикл было бы неудобно, поэтому я использую итератор, который просто «плюется» нотами в медиаплеер.



Предпосылки для появления генераторов возникли уже давно. Вы можете увидеть динамику популярности Node.js за последние пять лет, она косвенно отражает популярность JavaScript в целом. Также на график отражает частоту запроса Callback Hell — он пропорционально зависит от распространения JavaScript. То есть, чем популярнее становился JavaScript, тем больше страдали разработчики и клиенты.



Лапша, представленная на изображении – это структурная визуализация кода, написанного без генераторов. То есть это то, с чем всем нам приходится работать – мы к этому привыкаем и, не имея выбора, воспринимаем как данность. Когда разработчики начали попытки борьбы с этим явлением, появилась такая штука как promise. Идея была в том, чтобы взять все наши Callback (функции обратного вызова) и «размазать» их по всему коду, объявляя там, где нам удобнее. Однако на самом деле у нас остались те же самые функции обратного вызова, просто представленные в немного другом виде. Разработчики продолжили борьбу – так появились генераторы и асинхронные функции.

Генераторы


Применение
• Написание синхронного кода.
• Написание приостанавливаемых функций.
• Написание комплексных итераторов.

Генераторы позволяют писать синхронный код. Раньше я говорил, что достоинство JavaScript как раз в его асинхронности, теперь поговорим, как писать на JavaScript синхронный код. На самом деле, это код будет псевдосинхронным, поскольку Event Loop не будет останавливаться, если у вас есть какие-то тайм-ауты в фоне, пока вы будете ожидать выполнения приостановленного генератора. Вы вполне можете выполнять в фоновом режиме любые другие нужные операции. Мы можем написать приостанавливаемые функции, применение которых достаточно узко, в отличие от асинхронных действий, применяемых очень широко. Появилась и возможность написания комплексных итераторов. Например, мы можем написать итератор, который будет каждый раз ходить в базу и по очереди итерировать одно значение из нее.



Сверху и снизу вы видите абсолютно идентичные по функциональности сниппеты. У нас есть некая функция, которая должна сходить в базу данных и забрать user.payment_id. После чего она должна сходить на внешнюю API и забрать payment details user, актуальные на текущий день. У нас возникает явление The Pyramid Of Doom, когда функция обратного вызова находится внутри другой функции обратного вызова, и степень вложенности может увеличиваться бесконечно. Естественно, результат не всегда получается приемлемым, даже инкапсулировав все операции в отдельные функции, на выходе мы все равно получаем «лапшу».

Есть решение, которое позволяет нам сделать то же самое с помощью генератора: у генератора немного другой синтаксис — function* (со звездочкой). Генератор может быть именованный и неименованный. Как вы можете видеть, у нас появилось ключевое слово yield. Оператор yield, который приостанавливает выполнение генератора, позволяет нам дождаться выполнения метода GetUser. Когда мы получим данные, положим их в user, после чего продолжим выполнение, таким же образом получим paymentDetails, и тогда сможем отрисовать всю информацию для нашего пользователя.



Рассмотрим возможность реализации генераторов — как мы можем их перебирать. Здесь мы видим уже описанную ранее конструкцию. Как было показано на итераторе, здесь тоже есть итератор числа, который будет нам возвращать значение от 0 до 3, и который мы будем перебирать. То есть, мы можем использовать метод next.

Метод next()


• Может принимать в качестве аргумента значение, которое будет проброшено в генератор
• Возвращаемое значение – объект с двумя ключами:
value — часть выражения, получаемая из генератора.
done — состояние генератора.

Метод next ничем не отличается от аналогичного в итераторах, мы можем получить value и done, как два параметра, можем пробросить значение в генератор и получить значение из генератора.



Следующий вопрос — производительность. Насколько имеет смысл использовать то, о чем мы говорили? На момент доклада средств тестирования в моем распоряжении не было, поэтому я написал свое. В результате тысячи итераций удалось добиться среднего значения по различным технологиям. В Chrome обещания и генераторы не сильно отличаются друг от друга, причем в большую сторону отличаются то одни, то другие. Если учесть, что время, затраченное на выполнение одной итерации с помощью Callback, Promise или генераторов, исчисляется в миллисекундах, в реальности особенной разницы нет. Я думаю, что заморачиваться, экономя на спичках, не стоит. А значит, можно свободно использовать то, что вам больше по душе.



Ни один современный доклад о JavaScript не может обойтись без React. Я в частности буду говорить о Redux.

redux-saga


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

В функциональном программировании есть очень важный принцип — мы должны использовать «настоящие функции». Наша функция не должна влиять на окружение, должна работать с теми аргументами, которые мы ей передаем. В том или ином виде наши функции обратного вызова часто превращаются в impure function, и этого, конечно, хочется избежать. Отсюда и основное назначение redux-saga — возможность писать синхронный (псевдосинхронный) код.



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



Суть достаточно проста: в результате мы выполнили асинхронное действие очень просто и быстро. Собственно, минимальная saga выглядит так: есть генератор, который обращается к нашей saga, вызывает takeEvery — один из методов saga, который позволяет нам инициировать событие “USER_FETCH_REQUESTED” внутри нашего редюсера. Возможно, вы обратили внимание, что yield здесь идет со звездочкой. Это является делегацией операции генератора, мы можем делегировать наш генератор другому генератору.

redux-saga: послесловие


• Саги (Sagas) не декларируются, как обычные Actions, их необходимо внедрять через sagaMiddleware.
• Очевидно, что сам sagaMiddleware — нечто иное, как middleware вашего store в Redux.

Мы поговорили про фронтенд, теперь пришло время рассказать про бэкенд, т. е. о koa. Я сталкивался со многими фреймворками на бэкенде, наиболее интересными для меня показались kraken.js и koa.js, на втором остановлюсь подробнее.

koa.js


В двух словах это:
• node.js-фреймворк для серверной разработки.
• node.js-фреймворк, который использует ES6-генераторы, асинхронные функции ES2016.
• node.js-фреймворк, написанный командой express.js.


Учитывая авторитетность команды express.js, ресурсы компании, фреймворк вызывает доверие и быстро развивается. На данный момент вокруг него образовалось солидное сообщество, он оброс кучей библиотек — зачастую найти какое-то решение для middleware koa очень просто.

• «Фреймворк нового поколения»



Что такое koa? По сути, это фреймворк, который предоставляет нам движок для посредников (middleware), а их архитектурная диаграмма очень похожа на хорошо знакомую всем игру в испорченный телефон. Здесь имеется состояние, которое по очереди передается между middleware, каждый из которых влияет или не влияет на это состояние (я дальше покажу пример логера, который влияние не оказывает). С этим middleware мы и будем работать. Напомним, что koa.js — фреймворк middleware на генераторах. Т. е., если мы говорим о маршрутизации, о различных полезных HTTP-методах, о системах безопасности, защите от CSRF-атак, о кроссдоменных запросах, шаблонизаторах и т. д. — в koa ничего этого мы не найдем. В koa есть только движок для middleware, причем множество из них написано самой командой koa.js.



Так выглядит максимально простое приложение на koa.js. Есть реализация логирования – простейшая имплементация middleware на koa.js. Это генератор, который возвращает свое состояние и перед тем, как его вернуть, и после того, как оно вернется, что позволяет подсчитать время, затраченное на выполнение нашего приложения. Обратите внимание, что выполняются они в порядке объявления: то, что объявили выше, начнет работать прежде всего.

koa.js


Преимущества:
• Наличие огромного количества библиотек, обернутых в co.js.
• Модульность и легковесность.
• Возможность писать более понятный код.
• Возможность писать меньше кода.
• Высокая активность сообщества.

Казалось бы, koa.js — бедный фреймворк, в котором нет почти ничего. В то же время, существует множество библиотек, и большая часть стандартного сервисного функционала представлена в виде middleware. Нужны кроссдоменные запросы — просто подключаете пакет и пробрасываете middleware. Если требуются настройки — необходимо просто передать параметры, и у вас будут кроссдоменные запросы. Необходима авторизация с помощью jwt- token — то же самое: понадобятся три строчки кода. Если необходимо работать с базой данных — пожалуйста.

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



В таблице представлено сравнение поставки Koa, Express и Connect фреймворков. Как вы можете видеть, в koa нет ничего, кроме middleware ядра.

Стоит сказать пару слов о самом co.js:

Co.js — это обертка вокруг генераторов и обещаний, которая позволяет нам упростить работу с асинхронными операциями. Более корректно обозначить co как «Сопрограммы (coroutines) в JavaScript». Идея сопрограмм не нова, и существует в других языках программирования очень давно.

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

Если привести все к более привычным для JS-разработчика материям — co.js выполняет генератор, избавляя нас от необходимости последовательного вызова next() генератора. В свою очередь co возвращает другое обещание, что позволяет нам отследить его завершение и отловить ошибки (для этого можно использовать метод catch). Самое крутое — в co можно выполнить yield для массива промисов (а ля Promise.all). Стоит заметить, что co прекрасно справляется с делегацией генераторов.

koa.js


Пара полезных пакетов для старта:

• koa-cors — разрешаем кроссдоменные запросы одной строкой.
• koa-route — полноценный роутинг.
• koa-jwt — cерверная реализация авторизации с использованием jwt-токена.
• koa-bodyparse — парсер тела приходящих запросов.
• koa-send — управление статикой.

Выше в качестве примера приведены несколько middleware, которые вы можете использовать в реальном приложении. koa-cors пакет позволяет обеспечить кроссдоменные запросы, koa-route обеспечивает роутинг, аналогичный тому, что есть в Express, и т. д.



Основные недостатки koa.js — обратная стороной того, что фреймворк поставляется голым, необходимость постоянно контролировать качество пакетов, которые при этом не обещают быть зависимыми друг от друга, и иногда избавляться от багов становится сложно. Вторая проблема — подбор команды, потому что на данный момент, к сожалению, с koa.js работает не так много людей. Из-за этого увеличивается время на введение нового человека в проект. И если проект маленький, это может оказаться нерентабельным. Т. ч. использовать koa.js в работе нужно с умом.

koa.js 2


Фреймворк нового поколения?

Koa.js 2 — очень хитрый фреймворк. Он работает на спецификации, которой нет. То есть вы можете найти статьи об асинхронных функциях, где сказано, что это ECMAScript 7 или ECMAScript 2016. Но самом деле несмотря на то, что Babel, Google Chrome и Microsoft Edge поддерживают асинхронные функции, их не существует. Многие ожидали, что асинхронные функции войдут в официальный релиз ECMAScript 7 (2016), но в итоге тот вышел с исправлениями дефектов и двумя новыми возможностями, чем новшества и ограничились. А тем временем koa.js 2 на асинхронных функциях работает, разработчики на них пишутся. И все это позиционируется как фреймворк нового поколения.

Async functions


Обзор
• Async — это Promise.
• Await — это Promise.

Асинхронные функции — и Async, и Await — это Promise.



Допустим, у нас есть такой код. Если убрать async и await, поставить возле функции звездочку и поставить yield перед conquer, получится генератор. Казалось бы, в чем разница? А она в том, что мы ожидаем в conquer обычный Promise, не надо оборачивать наши асинхронные функции ни в какие генераторы, это просто не требуется — мы можем взять обычный новый метод для получения запроса сервера fetch. Потом необходимо дождаться результата, а когда мы его получим, положим в state и таким образом вернем состояние.

Async functions


Послесловие
• Асинхронные функции удобнее генераторов (меньше кода, нет необходимости оборачивать промисы для генераторов).
• Асинхронные функции пока еще не часть стандарта и не ясно, станут ли они его частью.

Асинхронные функции, безусловно, удобнее генераторов, они позволяют нам писать меньше кода. В этом случае нет необходимости писать обвязочный код, можно взять любую библиотеку, которая возвращает нам promise (а это почти все современные библиотеки). Это позволяет сэкономить много времени и денег. Минус — асинхронная функция — все еще черновик спецификации. Значит, в итоге может получиться так же, как с захватом экрана в WebRTC: появились приложения использующие эту функциональность, а в результате от нее отказались.



Мораль всего, о чем я рассказывал в статье, довольно проста: я не говорю, что генераторы —замена Promise или Callback. Я не утверждаю, что асинхронные функции могут заменить генераторы, функции обратного вызова и обещания. Но у нас появились новые инструменты для написания кода, позволяющие делать его красивым и структурированным. Но их использование остается на вашем усмотрение. Решать стоит с точки зрения рациональности и применимости каждого инструмента в конкретно вашем проекте.

Список используемых ресурсов


Рисунки заимствовал тут: 1, 2, 3.

Сниппеты заимствовал тут.
DataArt 95,44
Технологический консалтинг и разработка ПО
Поделиться публикацией
Похожие публикации
Комментарии 26
  • +2

    Но ведь и для express можно написать обработчик роута в async/await стиле:


    app.get("/url", async function(req, res, next) {
      let list = await getListFromDb();
      lst processedList = await processList(list);
      res.send(processedList)
    })
    • +2
      То есть коллбэк хелл, который обычно банально означает малый опыт работы с JS, мы теперь заменяем семантическим адом.
      • 0
        Поделитесь, пожалуста, примером как избежать колбэк-хелла без промисов и их производных.
        • +2
          Создавайте больше методов с небольшим количеством вложенных колбеков или используйте библиотеку асинк. Это не рекомендация промисы с асинк/евейт это здорово, но избежать ада можно было и без этого =)
          • 0
            Модуляризация, наличие конвенции о размещении коллбэков в сигнатурах, наличие центральных оркестраторов приложения вроде стейт машин или механизма эвентов, хотя у последнего есть множество своих минусов.

            И почему без промисов? Они по сути просто удобная обертка над двумя-тремя коллбэками. Стоит познакомиться с FRP это развитие идее, когда мы вместе с коллбэками упаковываем контекст выполнения, и по возможности оформляем код как мэппинг входного потока данных на выходной.

            Еще очень полезно познакомиться с другими функциональными языками программирования, например LISP/clojure или Haskell, в них многие вещи вроде мэппингов, функторов, делегатов, монад и т.п. более наглядны без шелухи си-подобного синтаксиса.
            • 0
              Поделитесь, пожалуста, примером как избежать колбэк-хелла без промисов и их производных.

              В целом, меня всегда веселило непонимание огромного количества разработчиков истинных причин возникновения callback hell. Причина не в мифических нюансах асинхронности кода, как считают многие, а в банальной моде на использование АНОНИМНЫХ функций и раз уж Вы задали это вопрос, ок, я открою Вам глаза на сколько всё на самом деле просто :)
              Я намеренно буду использовать синтаксис ES5, что бы всё было так, как у меня в коде на node.js версии 0.2.4, когда хайп проблемы только зарождался и такие решания как промисы и deffered были ещё не на слуху.
              Рассмотрим типичный callback hell:
              asyncFn1(function () {
                asyncFn2(function () {
                  asyncFn3(function () {
                    asyncFn4(function () {
                      someTargetAction();
                    })
                  })
                })
              })
              

              Сегодняшние кодеры, сталкиваясь с этой проблемой сразу находят с инете ответ — юзайте промисы! и это правильный ответ, я рад, что недопонимание сути проблемы привело к появлению такого замечательного инструмента, но на деле решить проблему можно просто перестав использовать анонимные функции в качестве функций обратного вызова, тупо объявив их явно перед использованием:
              function callbackFn1() {
                asyncFn2(callbackFn2)
              }
              
              function callbackFn2() {
                asyncFn3(callbackFn3)
              }
              
              function callbackFn3() {
                asyncFn4(callbackFn4)
              }
              
              function callbackFn4() {
                someTargetAction()
              }
              
              asyncFn1(callbackFn1)
              

              И да, разумеется с промисами код на много лаконичней:
              asyncFn1()
              .then(asyncFn2)
              .then(asyncFn3)
              .then(asyncFn4)
              .then(someTargetAction)
              

              Но ради всего святого, раздуплитесь уже наконец в первопричинах проблемы, что бы не задавать больше таких вопросов и если у Вас сложная нестандартная ситуация, в которой Вам очень сложно найти правильное решение, как вариант — объявите все анонимные функции явно и взгляните на свой код в детально расписанном виде — даже сама непонятная проблема на деле может оказаться весьма банальной :)
            • 0

              deleted

            • +3

              Вы переворачиваете все с ног на голову и запутываете новичков. Вы начинаете с того, что «генераторы позволяют писать синхронный код». Бог с ней, с формулировкой (правильно было сказать «генераторы позволяют писать асинхронный код в синхронном стиле»). Но ведь это откровенная неправда. Генераторы знать ничего не знают о синхронности или асинхронности вашего кода. Они — простой способ записи итераторов. Удобный способ описания и работы с последовательностями данных. Это фреймворки, использующие генераторы, позволяют что-то там делать с кодом.

              • +1
                Согласен, возьмем пример из статьи
                function* renderUserData(render) {
                    let user = yield getUser();
                    let paymentDetails = yield getUserDetails(user.payment.id);
                    render(paymentDetails);
                }
                

                первый yield вернет user? Нет, он вернет promise, которого где то снаружи функции нужно дождаться, чтобы снова вызвать next(), тоже самое для getUserDetails(). Код не полный, а приводится как довод в пользе генераторов.
                • 0
                  В том примере опущен вызов функции rendrer для случаем с промисами в том числе, это не ошибка. Основной идеей было описать принцип работы без контекста его вызова.
                  • +1
                    Сверху и снизу вы видите абсолютно идентичные по функциональности сниппеты.

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

                    // Вызов варианта с промисом
                    renderUserData();
                    
                    // Вызов варианта с генератором
                    let generator = renderUserData();
                    
                    generator.next().value
                        .then(user => generator.next(user).value)
                        .then(paymentDetails => generator.next(paymentDetails ).value)
                    
                    


                    Очень похоже на то, что мы использовали генератор ради использования генератора. Возможно вы скажете, что внешний вызов генератора можно отдать на откуп сопрограммам типа co.js — соглашусь, что это позволяет получать некий профит.

                    Смысл в том, что генераторами нельзя заменить промисы (для асинхронных вызовов). Вообще никак. Async\await — да, киллер фича, нас ждет светлое будущее (заглянуть в будущее уже можно с помощью babel и подобных)
                    • 0
                      Как по мне — идея «заменить генераторы промисами» в корне не верна. Мы вполне можем использовать промис внутри нашей сопрограммы и в результате выполнения промиса передавать управление генератору. В то же время, ничего нам не мешает использовать для асинхронного действия в сопрограмме функцию обратного вызова и решить задачу вообще без промисов.
                • 0
                  Спасибо за комментарий. В статье я раскрывал конкретно реальное использование генераторов в качестве сопрограмм. В частности раскрывается способность генераторов приостанавливать свое выполнение, которую мы и используем для нового способа реализации асинхронных действий.
                  Я везде писал «псевдосинхронный» вместо «синхронный» код. И почему же генераторы этого не позволяют? Вполне себе позволяют, хоть, как вы и говорите, ничего об асинхронном коде сами по себе знать не должны.

                  Ничего не мешает объявить генератор как переменную, например, myGenerator и внутри сопрограммы продолжить выполнение родительского генератора с помощью myGenerator.next().
                • +1
                  такие как Map, Set, WeakMap, WeakSet — все они должны содержать свой итератор

                  WeakMap, WeakSet — не содержат и не должны, иначе они бы не были Weak
                  • 0
                    Спасибо, полностью с этим согласен, исправили.
                  • +4
                    Если использовать промисы как коллбэки, то зачем их вообще использовать?
                    // Пример из статьи
                    (render) => {
                        getUser().then((user) => {
                            getUserPaymentDetails(user.payment_id).then((paymentDetails) => {
                                render(paymentDetails);
                            });
                        });
                    };
                    
                    // Без лишних скобок
                    (render) => {
                        getUser()
                            .then(user => user.payment_id)
                            .then(getUserPaymentDetails)
                            .then(render);
                    };
                    
                    • 0
                      Спасибо, дельное замечание, Ваш вариант выглядит лучше моего. Но возвращаясь к сути вопроса — у нас остается цепочка и необходимость определять новую функцию / метод для последующих действий в чейне.
                    • +1
                      Promises можно делать плоскими, не обязательно вкладывать друг в друга.
                      • 0
                        Вы имеете ввиду образование цепочек с помощью последовательного вызова .then() на примере выше?
                      • 0

                        Может немного оффтоп, но все же.


                        Странная мания пошла популяризировать фичи, которые еще не скоро появится. Да, у async-await — stage 3, но официальную публикацию спецификации планируют "аж" в 2017, а поддержка в браузерах и того боле. Все-таки, в мире javascript решения плодятся быстрее, чем дрожжи, и полгода-год — это очень много.


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


                        Все ИМХО

                        • 0
                          По поводу async-await, и babel, отлично себя показали в продакшене, по всем показателям, неговоря про удобство.
                          А на koa 2.x можно писать и на промисах, тут дело выбора написать так:
                          (render) => {
                              getUser()
                                  .then(user => user.payment_id)
                                  .then(getUserPaymentDetails)
                                  .then(render);
                          };
                          

                          или так
                          async function (render) {
                              let user = await getUser()
                              let paymentDetails = await getUserPaymentDetails(user.payment_id)
                              await render(paymentDetails)
                          };
                          

                          Посути async-await транспилится в тотже промис и возращает тоже промис.
                        • 0
                          Т. е., если мы говорим о маршрутизации, о различных полезных HTTP-методах, о системах безопасности, защите от CSRF-атак, о кроссдоменных запросах, шаблонизаторах и т. д. — в koa ничего этого мы не найдем.

                          В ядре нет, но все это есть в виде библиотек, заточеных именно под коа. Большенство сдесь. А остальное можна найти в npm
                          • 0

                            А почему бы в случае уже существующего express-проекта не взять bluebird и использовать его Promise.coroutine для обёртывания генераторов? Снаружи это выглядит, как обычный promise, который можно скормить в express, а внутри это выглядящий линейным код.
                            В принципе текущая реализация async-функций совместима с Promise и можно использовать её as is в свежих версиях node (6+?), как справедливо заметили выше.

                            • 0
                              Вариантов много, я привел лишь некоторые из них.

                              В хроме, кстати, тоже работает async await: https://www.chromestatus.com/feature/5643236399906816
                              Проблема async / await в том, что спецификация еще не утверждена. Маловероятно, но можно столкнуться с тем, что спецификация к окончательному утверждению документации может измениться (хоть это и маловероятно). В любом случае, тот же koa2 прекрасно работает с async / await.
                            • 0
                              Значит, в итоге может получиться так же, как с захватом экрана в WebRTC: появились приложения использующие эту функциональность, а в результате от нее отказались.

                              А можно про это подробнее?
                              • 0
                                В функциональном программировании есть очень важный принцип — мы должны использовать «настоящие функции».


                                Чистые же. Автор, неужели не сталкивались с этим термином? Или читаете только англоязычную литературу?

                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                Самое читаемое