Как 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 и генераторов вы можете найти в моём форке
Подписывайтесь на РСС. Всем добра!
фото: jdhancock
Похожие статьи:
-
Инструменты frontend-разработчика. Утилиты
-
Музыка для работы #5
Немного мурашек по спине…
-
Белый шум
Баттхёрта нить начинается здесь
-
CommonJS для браузера
Видео моего доклада на MoscowJS
-
Музыка для работы #4
Трогательный chillwave, dream pop & glich
-
Instapaper и Pocket
К чёртовой матери ссылки!
-
Byobu
Текстовый тайловый менеджер для Linux и OS X
-
Чейнинг
или Как сделать код проще, добавив одну строчку