Pull to refresh

Comments 26

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


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

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

Еще очень полезно познакомиться с другими функциональными языками программирования, например LISP/clojure или Haskell, в них многие вещи вроде мэппингов, функторов, делегатов, монад и т.п. более наглядны без шелухи си-подобного синтаксиса.
UFO just landed and posted this here

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

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

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

Но это не так, в случае с промисами вам достаточно вызвать функцию. В случае с генераторами вам нужно вызвать функцию и построить цепочку промисов самостоятельно, попутно возвращая в 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 и подобных)
Как по мне — идея «заменить генераторы промисами» в корне не верна. Мы вполне можем использовать промис внутри нашей сопрограммы и в результате выполнения промиса передавать управление генератору. В то же время, ничего нам не мешает использовать для асинхронного действия в сопрограмме функцию обратного вызова и решить задачу вообще без промисов.
Спасибо за комментарий. В статье я раскрывал конкретно реальное использование генераторов в качестве сопрограмм. В частности раскрывается способность генераторов приостанавливать свое выполнение, которую мы и используем для нового способа реализации асинхронных действий.
Я везде писал «псевдосинхронный» вместо «синхронный» код. И почему же генераторы этого не позволяют? Вполне себе позволяют, хоть, как вы и говорите, ничего об асинхронном коде сами по себе знать не должны.

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

WeakMap, WeakSet — не содержат и не должны, иначе они бы не были Weak
Спасибо, полностью с этим согласен, исправили.
Если использовать промисы как коллбэки, то зачем их вообще использовать?
// Пример из статьи
(render) => {
    getUser().then((user) => {
        getUserPaymentDetails(user.payment_id).then((paymentDetails) => {
            render(paymentDetails);
        });
    });
};

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

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


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


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


Все ИМХО

По поводу 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 транспилится в тотже промис и возращает тоже промис.
Т. е., если мы говорим о маршрутизации, о различных полезных HTTP-методах, о системах безопасности, защите от CSRF-атак, о кроссдоменных запросах, шаблонизаторах и т. д. — в koa ничего этого мы не найдем.

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

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

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

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

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


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