Nodejs. Побеждая ад

версия для печати

Черновик. В будущем планирую найти таки красивое решение и не катить бочку на nodejs =)

Применительно к ноде есть такое понятие, как "callback hell" (глубоко вложенные колбэки). На хабре есть об этом. В попытках избежать этой засады я стал разбирать код на части и попал в другой кошмарик, с ассинхронной работой. Конечно есть решения и в мануалах все просто. Но стоит написать в ноде что-то чуть сложнее "Hello, world!", как начинаются проблемы. Код с катастрофической скоростью обрастает парными скобками "})", анонимными функциями и вложенными callback-вызовами. На данном этапе работы с ним я искрене не понимаю, как можно тащиться от nodejs и компании.

Работаем с модулем async. Мануал по нему полезен чуть более, чем нисколько. Задача: нужно вызвать последовательно несколько методов так, чтобы следующий метод использовал результат предыдущего. При этом ловим ошибки разумеется. Даже в простом случае получаем такое:

var async = require('async');

var result; //итог работы серии методов

async.waterfall(
    [
        //Хрень первая: без обертки в анонимную функцию работать не будет.
        //Хрень вторая: назначить отдельную функцию в качестве callback нельзя.
        function(callback){
            //попытка разбить код на части. Выносим в отдельную процедуру
            externalFunc(callback);
        },

        function(ids, callback){
            //какие-то еще действия с данными от предыдущей функции
            ids += 6;
            callback(null, ids);
        },
    ],

    //Ошибки полученные в серии можно обработать только тут
    function(err, res) {
        if (err)
            //самый простой вариант
            console.log(err);
        else
            //отдаем наружу то, что получилось
            result = res;
    }
);

//.. и получим 0!
console.log(result);

function externalFunc(asyncback) {
    //Так превываем выполнение метода из серии
    //return asyncback(new Error('ops!'));
    ids = 1 + 4;
    asyncback(null, ids);
}

Много лишнего кода, но это жертва в пользу синхронности. Однако это не все. Если в externalFunc() будет вызов какой-нибудь функции (наследника EventEmmitter ?), способной затупить с ответом, то выполнение серии ее ждать не будет! Т.е. там нужно как-то организовать отдельный async.series(), который должен работать в паре с родителем.. Не уверен, что такое вообще возможно.

Еще одна засада: переданный наружу результат придет позже, чем наступит его очередь. Это потому, что все, что за пределами async.*, выполняется без ожидания серии. Т.о. если нужно продолжить работу с результатом серии, то только в самом async-блоке.

Если говорить о практической ситуации: получение данных через Sphinx + MySQL. Сначала нужно подключиться к Сфинксу, по запросу получить ids, потом подключиться к MySQL и по ids получить данные. Как я не изголялся, но моя серия упорно не хотела ждать, когда придет ответ от MySQL. А если добавить еще корректную реакцию на ошибки подключения с прерыванием выполнения программы, тогда начинается реальный ад. В итоге убив несколько часов я накатал код без разбиения на отдельные блоки. Прям так, портянкой, с кучей вложенных вызовов и tab-отступами на полстраницы. Прелесть..

Только вот не надо кидаться тапками, что мол, я нихрена не шарю и в nodejs не разобрался.. Я шарю, но не в ноде :) и считаю, что он реально не удобен для работы. Конечно, у него есть и плюсы, это мощная прокачка психики кодера :)

[1oo%, EoF]

Понравилась статья? Расскажите о ней друзьям:


Комментарии
Для работы модуля комментариев включите javaScript


Показать/скрыть правила
Имя
[i] [b] [u] [s] [url]
:-) ;-) :D *lol* 8-) :-* :-| :-( *cry* :o :-? *unsure* *oops* :-x *shocked* *zzz* :P *evil*

Осталось 1000 символов.
Код защиты от спама Обновить код
Каждый комментарий проходит ручную модерацию. 100% фильтрация спама.
Продвижение
Время
Метки