Как стать автором
Обновить

Комментарии 33

Тут есть маленькое отступление и сложность с которой я столкнулся. Если инициализацию сессий указывать после определения маршрутов, то сессии по какой-то причине на работают, по этому сессии инициализируем раньше.

Это не по какой то причине, а потому что express выстраивает цепочку вызовов из функций function(req, res, next) {… }. Отсюда и получается, что запрос попадает в ваш обработчик раньше чем в обработчик сессий (до него он даже не доходит).

И еще:
1) Чего подключение к базе делает в контроллерах?
2) использование глобал, путь на темную сторону.
1. Я придерживаюсь своего правила, что все что относится к базе должно быть выделено в отдельный модуль (класс/библиотеку), это лично мое правило, я никому его не навязываю и не вижу ничего критичного в выделении таких функций.
2. Если есть набор механизмов используемых во всех модулях, почему бы и нет.
Если такой подход не верный, расскажите как делать более правильно, это будет являться очень полезным знанием.
1. Да, аргумент про выделение в отдельный модуль/класс/библиотеку верный, но контроллеры то причем?
Вы правы, правы и те кто осудил само название модулей и подход. Спасибо за критику, она натолкнула на идею реализации MVC в более менее полном объеме и на основе классов
Почему решили использовать именно Node и MongoDB?
Они оба любят json :-).
Не нашел ссылку на github ;(
Вот скажите мне, только честно — от чего вы, юзая ООП-заточеный язык, не используете объекты?

Объекты — это хорошо.
Объекты придают функции контекст.
Объекты придают тестированию смысл.
Объекты наше все :)

PS. И вааще, CoffeeScript, jade и stylus придадут вам сил и бодрости, растраченные на расставление скобок и точек с запятыми :)
К слову, jade — один из самых медленных шаблонизаторов. Для обеспечения доступа к локальным переменным Jade использует конструкцию with, которая дико тормозит выполнение. В jade можно отключить использование with, передав в дополнительных параметрах self: true, насколько я помню. Это ускоряет его работу, но он всё равно остаётся одним из самых медленных. При этом, в таком режиме перед каждой переменной шаблона нужно будет писать префикс self., что сделает шаблоны уже не такими лаконичными.
Не такой уж и медленный jade без with — тык.
По моим подсчётам он остаёт от всех остальных. Я тестирую не в браузере, а в node.js.

Вот код бенчмарка: https://github.com/baryshev/template-benchmark.

А вот результаты на моей виртуалке с Ubuntu 12.04 и Node.js 0.8.9:

Rendering 100000 templates:

ECT
  Escaped   : 559ms
  Unescaped : 134ms
  Total     : 693ms

Eco
  Escaped   : 2625ms
  Unescaped : 491ms
  Total     : 3116ms

EJS
  Escaped   : 4621ms
  Unescaped : 2786ms
  Total     : 7407ms

Handlebars.js
  Escaped   : 521ms
  Unescaped : 275ms
  Total     : 796ms

Hogan.js
  Escaped   : 889ms
  Unescaped : 720ms
  Total     : 1609ms

Swig
  Escaped   : 2052ms
  Unescaped : 369ms
  Total     : 2421ms

Dust
  Escaped   : 553ms
  Unescaped : 363ms
  Total     : 916ms

doT
  Escaped   : 1699ms
  Unescaped : 100ms
  Total     : 1799ms

Fest
  Escaped   : 418ms
  Unescaped : 202ms
  Total     : 620ms

Jade without `with`
  Escaped   : 4134ms
  Unescaped : 3255ms
  Total     : 7389ms

Jade
  Escaped   : 13495ms
  Unescaped : 12210ms
  Total     : 25705ms


Такие вещи предпочитаю перепроверять. Кстати, шаблон doT по Вашей ссылке вообще не валиден. Это можно проверить, вставив его и данные в демо-редактор на сайте разработчика. Даже если бы он был валиден, такое сравнение не приемлемо, т.к. в doT по умолчанию отключено экранирование данных, а во всех остальных оно по умолчанию включено. Отсюда его «хвалёная» скорость. Экранирование — самая тяжёлая операция для js-шаблонизаторов и использовать её стоит с умом. Не стоит экранировать все данные подряд.
В своём тесте я сравниваю для всех шаблонизаторов скорость с экранированием и без неё.
Ссылка на тесты отсюда, так что мопед не мой. doT без экранирования, как понимаю, приводился для примера, а не что бы погоняться. Да и даже у вас jade без with вполне на уровне используемого в статье ejs.
О, не знал.
С другой стороны в моем случае оно пофик — jade используется как сырец для парсинга в html на сервере, а на клиенте шаблоны работают eco (ну, точнее сделанные из eco шаблонов stitch-ем функции, вроде там все прилично внутрях)

PS. А вроде бы with предан анафиме и за его использование на кострах сжигают, не?
Да там за многое руки отрубать нужно, но от этого jade менее удобным шаблонизатором не становится.
Да, многое в нем приятно.
Особенно доставляет :coffeescript — маркер :)
— controllers (все объекты для работы с БД)

Эта фраза, мне кажется, требует от автора разворачивания понятия «контроллер» и вообще описания архитектурной схемы. Если примерять на MVC то, что я увидел то:
контроллеры по вашей схеме – это модели по MVC,
маршруты по вашей схеме – это контроллеры по MVC,
'/auth/register' – это маршруты по MVC, а то место, где они у вас собраны (под заголовком «настраиваем маршруты») – диспетчер;
Вроде бы так.
Тут есть маленькое отступление и сложность с которой я столкнулся. Если инициализацию сессий указывать после определения маршрутов, то сессии по какой-то причине на работают, по этому сессии инициализируем раньше.

Само собой, при поступлении запроса express прогоняет request и response по цепочке обработчиков, если обработчик, ответственный за сессию, стоит после роутера — маршруты получат эти объекты без подцепленной сессии.
После такого названия ожидал чего-то вроде если не дневника изучения node от нуля (или от уровня «я знаю, что такое apache») до «я понял, что на node писать лучше, чем на php/python/...». Открыл, а тут… :)

Знаете, могу сравнить разве со статьей под заголовокм «Изучая езду на автомобиле от начала до конца (часть 1)» и содержимым «Для начала обучения я прикупил гоночный болид, настроил его следующим образом, и собрался на гонки (о гонках в части 2)». Суровое у Вас такое «начало» получилось :)
Я подходил к написанию с какими-то базовыми знаниями по сайтостроительству и node.js, увы удовлетворяющих мои потребности туториалов не нашел и решил, что мой пройденный путь будет кому-то интересен и полезен
Так изложение пути классное, просто оно хотя бы «часть 3», но не 1 и не 2.

Может, напишете приквел? Уверен, многие были бы только рады, потому что этот пост написал по делу — наверняка и остальное у Вас получится изложить толково.

В любом случае спасибо за статью!
Попробуйте использовать библиотеку для flow-control, чтобы не плодить лапшевидный код. Например, async.
Или node-nextflow для CS
спасибо, не знал, буду изучать
Расскажите, пожалуйста, как прикрутить свою 404 ошибку, чтобы она была действительно 404 (возвращала этот код) и не убивала статику. Когда делал сайтик на nodejs, пришлось статику вынести в /static и через nginx прописать для нее отдельный location, а в express выставить последним маршрутом общий /*. Работало, но проблема с кодом ответа так и не решилась.
Как сделать это по уму?
Добавляем обработчик в конец цепочки express, т.е. в.т.ч. после статики. До него дело дойдет только если остальные не возвратят ответ. res.send принимает в качестве параметра и код ответа. res.status, res.statusCode
Я делал так:
В самом конце файла routes.js (у меня все маршруты в одном файле) вставляю примерно такой код:

app.use(errorNotFound);

function errorNotFound (req, res) {
    var html = utils.acceptHtml(req); 
// ф-ия acceptHtml смотрит заголовок запроса и -
// если true, то генерим ответ в виде html, иначе в json

    if (html) {
        res.writeHead(404);
        res.end('error 404\n' + 'url ' + req.url + ' (' + req.method +') was not found on the server.');
// res.end по желанию можно заменить например на res.render('404', { params: params })
    }
    else {
        res.json({ error: const.ERR_ROUTES_404 });
    }
}
НЛО прилетело и опубликовало эту надпись здесь
это одна сторона монеты, еще есть мамы с детьми за которыми нужно приглядывать. Если и кого есть желание, можно объединить усилия и сделать что-то полезное и бесплатное
НЛО прилетело и опубликовало эту надпись здесь
Предлагаю всех заинтересовавшихся собраться в одном месте и все обсудить, пишите в лс
По поводу оформления модулей: структура, которую я привожу ниже, кажется мне более изящной:
someunit.js
var someunit = function () {
    "use strict";
                                            // private переменные и методы
// ..
        
    return {
                                            // public переменные и методы
// ..
    
}();

module.exports = someunit;  
И ещё. Думаю, будет нелишним собрать в одном месте всякие полезные плюшки, типа такой:

    var mem,
        oldmem;

    setInterval(function () {                               
// выводим кол-во занимаемой памяти только если оно изменилось с последнего замера
        mem = process.memoryUsage().rss;
        if (mem != oldmem) {
            console.log('Memory usage, MB: ' + (mem / (1024 * 1024)).toFixed(3));
        }
        oldmem = mem;
    }, const.MEM_OUTPUT_INTERVAL);


Так, тестируя проект, можно интерактивно наблюдать за кол-вом потребляемой памяти. Впрочем, сейчас есть куча способов следить за этим с помощью стороннего софта, но вышеприведённый код я написал ещё давно, хех.
exports.getlogin = function(req, res){
   // login
   return;
}

у вас все функции созданы с 2 параметрами и везде обязательно понатыканы return; которые на самом деле не нужны будут если придерживаться рекомендациям разработки в express (connect), а именно использования параметров с возвратом ошибок и единой обработкой их, тогда ваши функции станут выглядеть вот так:
exports.getlogin = function(req, res, next) {
   // logic
   if(err) next(new Error('My custom message error'));
}

и по ссылке посмотрите примеры обработчиков, который добавите в конец после всех роутов, тогда они будут перехватываться в случаи ошибки и будет единый обработчик, который можно стилизировать под json или html или и то и то прописав логику. А если пойти дальше, то можно унаследовать свои функции от Error и сделать разновидности ошибок, я использую например так:
// Error handling
app.use(function(err, req, res, next){
    console.log(err);
    if (err instanceof NotFound) {
        res.render('errors/404', {
            title : 'Not Found',
            layout: 'login/layout',
            status: 404
        });
    } else if (err instanceof AccessDenied) {
        res.render('errors/403', {
            title : 'Not Found',
            layout: 'login/layout',
            status: 403
        });
    } else if (err instanceof Unavailable) {
        res.render('errors/503', {
            title : 'Not Found',
            layout: 'login/layout',
            status: 503
        });
    } else if (err instanceof Offline) {
        res.render('errors/offline', {
            title : 'Offline',
            layout: 'login/layout'
        });
    } else {
        res.render('errors/500', {
            title : 'The Server Encountered an Error',
            layout: 'login/layout',
            error: err,
            status: 500
        });
    }
});

function AccessDenied(msg) {
    this.name = 'AccessDenied';
    Error.call(this, msg);
    Error.captureStackTrace(this, arguments.callee);
}
function NotFound(msg) {
    this.name = 'NotFound';
    Error.call(this, msg);
    Error.captureStackTrace(this, arguments.callee);
}
function Unavailable(msg) {
    this.name = 'Unavailable';
    Error.call(this, msg);
    Error.captureStackTrace(this, arguments.callee);
}
function Offline(msg) {
    this.name = 'Offline';
    Error.call(this, msg);
    Error.captureStackTrace(this, arguments.callee);
}
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории