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)
})
И почему без промисов? Они по сути просто удобная обертка над двумя-тремя коллбэками. Стоит познакомиться с FRP это развитие идее, когда мы вместе с коллбэками упаковываем контекст выполнения, и по возможности оформляем код как мэппинг входного потока данных на выходной.
Еще очень полезно познакомиться с другими функциональными языками программирования, например LISP/clojure или Haskell, в них многие вещи вроде мэппингов, функторов, делегатов, монад и т.п. более наглядны без шелухи си-подобного синтаксиса.
deleted
Вы переворачиваете все с ног на голову и запутываете новичков. Вы начинаете с того, что «генераторы позволяют писать синхронный код». Бог с ней, с формулировкой (правильно было сказать «генераторы позволяют писать асинхронный код в синхронном стиле»). Но ведь это откровенная неправда. Генераторы знать ничего не знают о синхронности или асинхронности вашего кода. Они — простой способ записи итераторов. Удобный способ описания и работы с последовательностями данных. Это фреймворки, использующие генераторы, позволяют что-то там делать с кодом.
function* renderUserData(render) {
let user = yield getUser();
let paymentDetails = yield getUserDetails(user.payment.id);
render(paymentDetails);
}
первый yield вернет user? Нет, он вернет promise, которого где то снаружи функции нужно дождаться, чтобы снова вызвать next(), тоже самое для getUserDetails(). Код не полный, а приводится как довод в пользе генераторов.
Сверху и снизу вы видите абсолютно идентичные по функциональности сниппеты.
Но это не так, в случае с промисами вам достаточно вызвать функцию. В случае с генераторами вам нужно вызвать функцию и построить цепочку промисов самостоятельно, попутно возвращая в 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);
};
Может немного оффтоп, но все же.
Странная мания пошла популяризировать фичи, которые еще не скоро появится. Да, у async-await — stage 3, но официальную публикацию спецификации планируют "аж" в 2017, а поддержка в браузерах и того боле. Все-таки, в мире javascript решения плодятся быстрее, чем дрожжи, и полгода-год — это очень много.
Вся эта катавасия, с новыми фишками, вынуждает использовать всякие 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: появились приложения использующие эту функциональность, а в результате от нее отказались.
А можно про это подробнее?
В функциональном программировании есть очень важный принцип — мы должны использовать «настоящие функции».
Чистые же. Автор, неужели не сталкивались с этим термином? Или читаете только англоязычную литературу?
Использование ES6 генераторов на примере koa.js