РСС

Ношу шлем, тяжело дышу…

Меня зовут Антон Шувалов. Я работаю в Lazada. Кроме программирования я пишу музыку и иногда занимаюсь дизайном интерфейсов. Я есть в Twitter, Facebook, и на GitHub. Вы можете написать мне email.

Если вы задумали порадовать меня небольшим подарком (не может быть!) — вот список моих мещанских мечт.

Как yield изменит Node.js

'Как yield изменит Node.js'

С выходом версии v0.11.2 Node.js обзавелся поддержкой v8-генераторов. Генераторы не легки для понимания, но, в общем, это что-то вроде оберток над функциями, которые могут выполняться множество раз, продолжая выполнение в различных местах функции.

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

Использование yield

Пример кода заменяет тысячу слов, так что давайте смотреть. Нам понадобится Node v.0.11.2, которую легко установить с помощью nvm (прим. переводчика: мне больше нравится n).

nvm install 0.11.2

Мы будем использовать основанный на промисах сервер под названием mach, и библиотеку для работы с промисами — Q. Вам нужно установить оба модуля через npm, если вы это еще не сделали.

Затем, так как мы используем новейшие фичи из v8, нам нужно указать флаг --harmony при запуске Node.

node --harmony ./generators.js

Давайте создадим функцию sleep(), которая принимает время ожидания в миллисекундах и возвращает промис, который разрешится по истечению времени.

function sleep(millis) {
  var deferredResult = Q.defer();
  setTimeout(function() {
    deferredResult.resolve();
  }, millis);
  return deferredResult.promise;
};

Типичный сервер на основе коллбеков будет использовать чейнинг промиса, примерно так:

var mach = require('../lib');
var app  = mach.stack();
var Q    = require('q');

app.run(function(request) {
  return sleep(2000).then(function(){
    return 'Good day to you sir';
  });
});

mach.serve(app, 3333);

А теперь сделаем то же самое, но с генераторами. Определим функцию-генератор через нотацию со знаком *. Внутри такой функции мы можем использовать yield, передав ему sleep()-промис.

app.run(Q.async(function *(request) {
  yield sleep(2000);
  return 'Good day to you sir';
}));

Как только yield будет вызван, выполнение функции остановится и перейдет обратно к Q.async(). Когда промис будет разрешен, Q обеспечит возврат к выполнению генератора. В нашем случае, это произойдет как только сработает таймаут. Q.async(), в свою очередь, так же возвращает промис в mach, который обрабатывает запросы к node-серверу.

yield деле

Пример со sleep() может показаться бесполезным, так что давайте посмотрим что-нибудь получше. Скажем, доступ к обработанному содержимому запроса. Mach возвращает его в виде промиса с помощью метода request.parseContent(). Так как это промис, мы можем передать его прямо в yield:

app.run(Q.async(function *(request) {
  var body = yield request.parseContent();
  return JSON.stringify(body);
}));

С использованием yield ваши обработчики становятся проще. Еще один пример с сохранением модели.

app.post('/users', Q.async(function *(request) {
  var user = new User(request.params);

  if (yield user.save()) {
    return JSON.stringify(user);
  } else {
    return 422;
  }
}));

Развитие yield

Мне приятно думать, что yield способен изменить написанные в традиционном спагетти-стиле node-приложения, сделав их чище. Я просто не могу дождаться поддержки браузеров, хотя, пожалуй, это произойдет еще не скоро.

Полный пример использования Mach и генераторов вы можете найти в моём форке

Как yield изменит Node.js

Подписывайтесь на РСС. Всем добра!

фото: jdhancock

«Как рушатся комплексные системы», Ричард И. Кук
О фундаментальных проблемах больших запутанных систем
7 паттернов для рефакторинга JavaScript-приложений
Перевод отличной серии статей о проектировании и рефакторинге проектов
Музыка для работы
Мои плейлисты: теплый glitch, нежные девичьи голоса, интересная электроника и chillwave
Ссылколог
Коллекционирую полезные ссылки