Это первая из серии запланированных статей, посвященных Коа 2.

Предварительные требования: знайте, что Koa - это сверхлегкая платформа веб-приложений для Node, ранее использовавшая промежуточное ПО на основе генератора. Общие сведения о функциях генератора и async / await (см. YDKJS Book 5 - это может занять несколько дней, но оно того стоит).

Теперь, когда у нас есть Async / Await без флагов на Node 7.6, мы можем перестать использовать грубые звездочки и начать использовать сексуальные стрелочные функции. На самом деле это поднимает хороший вопрос; действительно ли конечный пользователь приносит (kik) какие-либо неповерхностные улучшения, переходя на Koa 2? Да, возможно.

Вместо того, чтобы полагаться на модуль совместной подпрограммы co, выполняемый во время выполнения, чтобы присоединить решения к нашим обещаниям с вызовом функции для следующего промежуточного программного обеспечения, Koa перекладывает это на механизм (узел). Это почти наверняка влечет за собой превосходную производительность благодаря возможности оптимизации двигателя. Это также, вероятно, означает меньший размер приложения. В целом это также означает менее непонятное и более портативное промежуточное программное обеспечение благодаря соблюдению стандартизированных методологий ECMA.

Быстрое обновление при использовании Koa 2 в качестве потребителя

Давайте сделаем простое приложение Koa 2. Очевидно, нам сначала нужно yarn add koa (или npm i koa (pleb)).

koa = require('koa'); // We need Koa
app = new koa(); // Koa 2 is defined with ES6 class syntax
app.use(async (ctx, next) => {
  console.log('1. This');
  // Await all successive middleware before continuing:
  await next();
  console.log('6. app.');
});
app.use(async (ctx, next) => {
  console.log('2. is');
  // Await all successive middleware before continuing:
  await next();
  console.log('5. 2');
});
app.use(async (ctx, next) => {
  console.log('3. a');
  // No more middleware left, we don't need a next() here but Koa will automatically fill it with null anyway:
  await next();
  console.log('4. Koa');
});
http.createServer(app.callback()).listen(3000);
/* Same as the short form sugar app.listen(3000) */

Итак, когда мы запускаем это и отправляем любой HTTP-запрос этому приложению, мы получаем результат:

1. This
2. is
3. a
4. Koa
5. 2
6. app

Что здесь происходит?

Поскольку они определены в вашем коде, каждый компонент промежуточного программного обеспечения, который вы регистрируете в Koa.prototype.use, добавляется в стек промежуточного программного обеспечения (простой массив) в том порядке, в котором вы их регистрируете.

Стек используется нашим обработчиком app.callback (), определенным выше. Во-первых, каждый раз, когда сервер получает запрос, Koa сначала создает очень аккуратно организованный объектctx (контекст) с:

  1. Геттеры, которые позволяют получить доступ к заголовкам и телу HTTP (хотя вам понадобится промежуточное ПО, чтобы делать что-нибудь полезное с телом)
  2. Установщики, которые позволяют вам установить параметры для ответа на запрос.

Затем Koa вызовет стек промежуточного программного обеспечения. Koa вызывает каждую функцию промежуточного программного обеспечения одну за другой, рекурсивно из предыдущей функции. Это означает, что каждый вызов next () внутри любого промежуточного программного обеспечения будет инициатором для каждого последующего промежуточного программного обеспечения. Таким образом, если мы вызываем await next(); на нашем первом промежуточном программном обеспечении (как у нас), мы говорим Koa дождаться завершения всего следующего промежуточного программного обеспечения, прежде чем мы продолжим выполнение кода.

Что, если бы мы удалили await ключевое слово и просто запустили next() в одиночку? Давайте попробуем это на первом промежуточном программном обеспечении. Мы получаем следующий результат:

1. This
2. is
3. a
4. app.
5. Koa
6. 2

Это довольно дико, и его нелегко распознать без небольшого знания цикла обработки событий JS. Здесь происходит то, что каждый вызов next() оценивается синхронно. Когда мы дойдем до последней части промежуточного программного обеспечения, мы снова await. Мы больше не просто выполняем синхронный код, мы неявно преобразовали выражение, возвращаемое await, в обещание. Как и при использовании Promise#then, ключевое слово await означает, что мы не будем выполнять код обработки до тех пор, пока текущий поток не завершится, т.е. на этом этапе мы откладываем код после наших операторов await в очередь заданий, которая будет выполняться после завершения нашей первой части промежуточного программного обеспечения.

Если вы все еще не понимаете, я настоятельно рекомендую прочитать серию статей о YDKJS. В частности: книга 5. Если вы думаете, что я ошибаюсь или мог бы выразиться более четко, напишите мне в комментариях.

В течение следующей недели я напишу еще несколько статей о Koa 2. План такой:

Часть 2: Внутри машины - здесь будет рассмотрено очень простое ядро ​​промежуточного программного обеспечения и все объяснено в этой статье с прямой ссылкой на код Koa.
Часть 3: Объект ctx, HTTP и синтаксический анализ тела
Часть 4: Создание собственного маршрутизатора - здесь будет показано, как структурировать приложение Koa таким образом, чтобы оно было эффективным и простым в обслуживании.