понедельник, 16 сентября 2013 г.

Nodejs. Как же все таки работать с модулем Async

Node.js ворвалось на сервера с невероятной скоростью, ровно с такой же скоростью повергло в шок многих сервер-сайд разработчиков... Многим даже пришлось действительно изучить JavaScript и выйти за уровень jQuery подключателей :), но думаю одной из самых интересных и необычных сторон Node.js в частности и JavaScript в целом это его система колбеков, асинхронных вызовов. Потеряться во вложенности начинающему разработчику раз плюнуть.

Как полностью устроен принцип работы callback в node.js рассказывать не стану. Просто скажу, что первым параметром колбека всегда должен быть err объект или строка ошибки. Если внутри вашей пачки колбеков (в независимом скоупе есть еще череда колбеков), то у внутренних колбеков можно опустить параметр ошибки, т.к. эта пачка будет "видеть" общий для них объект ошибки, который можно смело передать в "выходной" колбек. Чего-то я какой-то замудренной фигни понаписал :), итак перейдем к инструменту который позволяет немного упростить и привести ваш код к более красивому и читаемому виду - это модуль Async, он позволяет навести порядки в ваших стеках колбэков. Итак приступаем. Первым делом добавляем в ваш package.json новую зависимость: "async": "*", после запускаем
npm install
Или же можно просто сделать так
npm install --global async
Эта команда установит Async глобально в вашу систему и будет доступен во всех проектах. Итак что нам может предложить Async для Node.js? А предложить он может многое стоит заглянуть для полного списка на его страничку github.org,я же приведу примеры для некоторых из них, и только из раздела control flow а именно:

Series — этот метод позволяет выполнять коллекцию задач по-порядку, и на выходе выполнить какой-нибудь полезный колбек. Этот метод полезен когда важен порядок выполнения, если можно так сказать то этот метод позволит вам "победить" асинхронность ноды:
var async = require('async')
  , tasksIndex = [
        function (callback) {
            // Вымышленный метод который вернет 231
            var viewsNumber = models.stat.viewsNumber();
            callback(null, viewsNumber);         
        }
      , function (callback) {
            // Вымышленный метод который вернет 24
            var growFactor = models.stat.growFactor();
            callback(null, growFactor);
        }
    ]
  , taskNamed = {
        viewsNumber: function (callback) {
            callback(null, models.stat.viewsNumber());
        }
      , growFactor: function (callback) {
            callback(null, models.stat.growFactor());
        }
    };

async.series(tasksIndex, function (err, results) {
    // Результат будет массивом
    console.log(results); // [231, 24]
});
async.series(taskNamed, function (err, results) {
    // Результат будет объектом 
    console.log(results); // {viewsNumber: 231, growFactor: 24}
});

Parallel — а этот метод работает в лучших традициях ноды, не нарушая ее асинхронности, но позволяет отследить конец работы всей пачки задач, т.е. все задачи выполняются параллельно и в конце результаты пробрасываются в финальный колбек. Листинг для этого метода практически ничем не будет отличаться от предыдущего, только надо вызвать не series а parallel

Waterfall — этот метод работает словно цепочка, результаты одной задачи передаются в колбеке следующей задачи, таким образом можно:
async.waterfall([
    function(callback){
        callback(null, 'один', 'два');
  , }
    function(arg1, arg2, callback){
        // Тут arg1 равен "один"
        // , а arg2 равен "два"
        // что соответствует второму и третьему параметру текщего колбека
        // , а первый конечно же мы не забыли - это err но в этом случае
        // ошибок нет поэтому null
        callback(null, 'три');
  , }
    function(arg1, callback){
        // Здесь же arg1 будет равен уже "три"
        callback(null, 'Готово');
    }
], function (err, result) {
   // Сейчас результат будет равен 'Готово'    
});

Собственно это основные методы по контролю за выполнением колбеков, который упростят работу с ними, для получения более подробной информации советую посетить страничку модуля на Github.