«Next generation web framework for node.js» — так написано в документации к версии 1.0. Звучит неплохо, я к этому добавлю что 2 года назад после внедрения koa на одном из проектов у наших программистов появился термин “псевдо-синхронный код” (Это когда код выглядит как синхронный но на самом деле исполняется асинхронно). Что за бред Как это работает я расскажу под катом.
Что такое KoaJS
Чтоб не повторяться:
С помощью особенности работы генераторов и директивы yield мы можем асинхронно выполнить Promise или специально нами сконструированную thinkify-функцию и после выполнения промиса/функции вернуться в ту точку где вызывался yield вернуть результат и продолжить выполнение кода.
Пример такого кода:
//...
let userId = Number(this.request.userId);
let projects = yield users.getActiveProjectsByUserId(userId); // Например, обращаемся к БД
for (let project of projects) {
project.owners = yield projects.getProjectOwnersById(project.id); // Тут тоже обращаемся к БД
}
this.body = yield this.render('userProjects', projects); // Тут асихронно рендерим ответ
//...
Зачем мне KoaJS?
Идея Koa идеально ложиться на парадигму микросервисов, которую я уже давно внедрил в нашей компании. Ядро фреймворка минималистично, код middleware для коа читается и понимается очень легко, что очень важно для командной разработки. Активное использоване фреймворком возможностей ES2015, минимальное травмирование психики программиста, который до этого писал на PHP (эти ребята колбеки не любят :) ).
Замечательно, чем удивит KoaJS 2.0?
То что было основой KoaJS, а именно библиотека co, построенная на генераторах теперь удалена из базовой реализации Koa 2.
Давайте посторим Hello world!
const Koa = require('koa');
const app = new Koa();
// response
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
Как видите тут генераторов нет, но тогда как же писать расхваленый мной “псевдо-синхронный код”. В самом простом случае можно обойтись нативным кодом:
app.use((ctx, next) => {
const start = new Date();
return next().then(() => {
const ms = new Date() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
});
next — является промисом, ctx — контекст запроса.
В таком виде без колбеков многие вещи реализовать нельзя, поэтому авторы предлагают использовать новый синкасис async/await, который еще не стал стандартом и нативно не поддерживается NodeJS но уже давно реализован в транспилере Babel. Выглядит это так
app.use(async (ctx, next) => {
const start = new Date();
await next();
const ms = new Date() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
Также предусмотрен вариант с дополнительным подключением библиотеки co и генераторами:
app.use(co.wrap(function *(ctx, next) {
const start = new Date();
yield next();
const ms = new Date() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
}));
Совместимость с Koa 1.x
Когда я говорил о “выпиленных” генераторах, то был не совсем точен. Для совместимости, если вы оформите middleware в стиле koa 1.0, koa 2.0 его подключит и исполнит он при этом в консоли будет “Koa deprecated Support for generators will been removed in v3…” Другими словами до версии 3.x все будет работать.
Вот пример:
// Koa will convert
app.use(function *(next) {
const start = new Date();
yield next;
const ms = new Date() - start;
console.log(`${this.method} ${this.url} - ${ms}ms`);
});
Также можно сконвертировать существующий middleware в формат 2.0 самостоятельно с помощью модуля koa-convert
const convert = require('koa-convert');
app.use(convert(function *(next) {
const start = new Date();
yield next;
const ms = new Date() - start;
console.log(`${this.method} ${this.url} - ${ms}ms`);
}));
В этом случае никаких предупреждений на консоль, поэтому я рекомендую использовать именно такой способ подключения legacy middleware.
Зачем переходить на 2.0
Конечно я не могу утверждать на 100%, но полгода стабильной работы одного из типовых сервисов дают мне уверенность в том что 2.0 достаточно стабилен.
Я хочу иметь право выбора каким способом реализовывать свой middleware. Koa 2.0 дает мне три пути: нативный, генераторы и async/await
Koa 2.0 уже поддерживают многие популярные middleware, а если не поддерживают, то работают через koa-convert
Если вы сейчас приглядываетесь к новым фреймворкам, попробуйте что-то небольшое закодить на Koa — уверен, Вы не пожалеете что потратите на это время.
Что посмотреть
- Документация по Koa 1.x
- Примеры на Koa 2.x
- Middleware для Koa
- Примеры небольших приложений на Koa
- Мой скелет REST-сервиса на Koa 2.0
- Скелет приложения на Koa2
- Шаблон для Koa2 c настроеным Babel
Автор: apelsyn