Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   Как вы пишете на сервере (node.js) (https://javascript.ru/forum/offtopic/47170-kak-vy-pishete-na-servere-node-js.html)

kobezzza 12.05.2014 21:31

Цитата:

Это даже не рекомендация, а обязательное правило, потому что catch может поймать только исключение в своем стеке.
В node есть модуль domain, который от части решает эту проблему. Также пляски с генераторами могут позволить юзать конструкцию try-catch, но ... это всё изврат, имхо :)

dmitry111 13.05.2014 01:10

Цитата:

Сообщение от kobezzza
2) Используй паттерны / фреймворки для работы с асинхронностью. Выбор фреймворка и паттерна зависит от предпочтений, я использую Async.

вот по поводу Async - как с ним работать?

Я понимаю для чего эти методы, но я не знаю где их применить
Например waterfall:

async.waterfall([
    function(callback){
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback){
      // arg1 now equals 'one' and arg2 now equals 'two'
        callback(null, 'three');
    },
    function(arg1, callback){
        // arg1 now equals 'three'
        callback(null, 'done');
    }
], function (err, result) {
   // result now equals 'done'    
});


обходит несколько функций, результат которых идет к следующей и так до конца. Но на деле то, как с этим работать?


У меня много моментов в коде, когда метод одного модуля задействует метод другого модуля.

Вот пример моего кода:

var config = require('../config');

var maxPlayers = config.get('game:maxPlayers');

// проверяет наличие свободные мест
// true: отсутствие мест
exports.check = function (users, cb) {
   var result

  // тут какие-то расчеты

  process.nextTick(function () {
    cb(result);
  });
};



var waiting = require('../lib/waiting');

var allUsers = 10;

waiting.check(allUsers, function (waiting) {
  if (waiting) { 
  } else {
  }
});


Передалось, расчеты сделаны, со следующим тиком callback вернет результат.

Где мне тут использовать этот async?

Также если есть примеры кода (или проект) с использованием async, поделись! А то статей про async много, а в рабочем исполнении не находил. По статьям невозможно понять как это все вместе работает ))

dmitry111 13.05.2014 01:19

Цитата:

Сообщение от melky
кстати, что ты имеешь в виду под "node.js" ? веб-сервер? так это ж только один компонент node.js

наверное ты имел в виду express\connect


имею в виду процесс взаимодействия модулей между собой. Не обязательно express\connect



Цитата:

Сообщение от melky
имхо, ответ дан на главной странице Node.js

я хочу сказать - ответ "везде, где есть ввод\вывод". но это я так думаю

вот я везде callback расставил, но это делает код менее понятным, ИМХО

Octane 13.05.2014 01:40

Цитата:

Сообщение от dmitry111
var config = require('../config');

var maxPlayers = config.get('game:maxPlayers');

// проверяет наличие свободные мест
// true: отсутствие мест
exports.check = function (users, cb) {
   var result

  // тут какие-то расчеты

  process.nextTick(function () {
    cb(result);
  });
};

А зачем колбек просто так асинхронным делать? Вместе с расчетами логично асинхронно запускать.
Так или иначе, скоро в Nodejs будут доступны встроенные ES6 Promises, думаю, это повлияет на API большинства новых модулей, а может быть и самого Nodejs, я бы уже начал писать асинхронные скрипты в таком стиле:
// проверяет наличие свободные мест
exports.check = function (users) {
    return new Promise(function (resolve, reject) {
        setImmediate(function () {
            try {                
                var value;
                // тут какие-то расчеты
                resolve(value);
            } catch (reason) {
                reject(reason);
            }
        });
    });
};

var waiting = require('../lib/waiting');

var allUsers = 10;

waiting.check(allUsers).then(function (value) {
    if (value) {
        //есть свободные места
    } else {
        //нет свободных мест
    }
}, function (reason) {
    //произошла ошибка
});

dmitry111 13.05.2014 02:12

Цитата:

Сообщение от Octane
А зачем колбек просто так асинхронным делать? Вместе с расчетами логично асинхронно запускать.

чтобы была пауза в работе.
До вызова callback происходят некоторые расчеты, далее пауза и вызов callback уже в порядке следующего тика.

melky 13.05.2014 08:58

Цитата:

Сообщение от dmitry111
обходит несколько функций, результат которых идет к следующей и так до конца. Но на деле то, как с этим работать?

везде, где есть асинхронные шаги в логике :) на практике чаще всего требовался parallel

зацени этот говнокод. рылся по истории git'а, чтобы специально показать тебе пример:

Задача: добавить категорию (родительскую\дочернюю - зависит от параметра запроса)

async.waterfall([

                    // тут получаем родительскую категорию, если можно
                    function (done) {
                        if (fields.id == -1) {
                            done(null, null);
                        } else {
                            models.ProductCategoryModel.findById(fields.id, function (err, parentCategory) { done(err, parentCategory); });
                        }
                    },

                    // тут определяем дочернюю категорию 
                    function (parentCategory, done) {
                        var newCategory;
                        if (parentCategory) {
                            newCategory = new models.ProductSubCategoryModel();
                        } else {
                            newCategory = new models.ProductCategoryModel();
                        }
                        newCategory.title = fields.new_category_name;
                        if (parentCategory) {
                            done(null, parentCategory, newCategory);
                        } else {
                            newCategory.save(function (err, newCategory) { done(err, parentCategory, newCategory); });
                        }
                    },

                    // связываем родительскую и дочернюю категории
                    function (parentCategory, childCategory, done) {
                        if (parentCategory) {
                            parentCategory.children.push(childCategory);
                            parentCategory.save(done);
                        } else {
                            done(null, null);
                        }
                    }

                ], function (err, parentCateg) {
                    if (err) return next(err);
                    allIsCompleted(err);
                });


Цитата:

Сообщение от dmitry111
вот я везде callback расставил, но это делает код менее понятным, ИМХО

вот для ухода от callback-hell используют async\Q\другое

kobezzza 13.05.2014 09:30

У меня самые частые - это waterfall и parallel

Пример с waterfall:
// Получение данных пользователя
async.waterfall([
    // Получаем данные пользователя по сессии
    function (cb) {
    },

    // Получаем данные пользователя по запросу
    function (sessionUser, cb) {
    },

    // Делаем проверку доступа и если всё ок, 
    // то отдаём данные
    function (requestUser, sessionUser, cb) {
    },
], callback);


Для задач дробления через setImmediate или nextTick прекрасно подходят циклы async:

var count = 0;

async.whilst(
    function () { return count < 5; },
    
    function (callback) {
        count++;
        
        setImmediate(function () {
            ...
            callback();
        });
    },
    
    function (err) {
        ...
    }
);


Цитата:

Так или иначе, скоро в Nodejs будут доступны встроенные ES6 Promises, думаю, это повлияет на API большинства новых модулей, а может быть и самого Nodejs,
На саму ноду не повлияет никак. Дело в том, что в первых версиях ноды были именно промисы, но от них отказались, т.к. они были чрезвычайно не эффективны для задач ноды.

Дело в том, что при работа на сервере в ноде часто работа идёт с потоками, т.е. данные принимаются / отдаются чанками, что полностью противостоит модели промисов, когда данные получаются сразу. Делается это, как я уже говорил, из соображений эффективности.

Так что какой-то революции нативные промисы не сделают, но всё же хорошо, что их добавят :)

melky 13.05.2014 09:41

Цитата:

Сообщение от kobezzza
Так что какой-то революции нативные промисы не сделают, но всё же хорошо, что их добавят

что такое "thunk" ?
раньше такого термина не встречал, а теперь он появился, вместе с появлением оператора yield

используется в этой либе: https://github.com/visionmedia/co

я так понял, с yield и thunk асинхронный код пишется, как синхронный. и он без callback'ов

UPD. вру :) thunk - частично исполняемая функция, которая принимает один аргумент - callback.
примерчики :
// read - это thunk
function read(callback) {
  fs.readFile('myfile.md', 'utf8', callback);
}
// readFile - генератор thunk'ов ?
function readFile(filename) {
  return function(callback) {
    fs.readFile(filename, 'utf8', callback);
  };
}

kobezzza 13.05.2014 09:50

Цитата:

что такое "thunk" ?
Тоже хз :) Я думаю, что это реализация либы, а не какая то нативная конструкция.

Цитата:

я так понял, с yield и thunk асинхронный код пишется, как синхронный. и он без callback'ов
Угу, сахарок :) Но, как я уже говорил, что я пока не вижу киллер фич :) И меня смущает, что в реализации на генераторах юзается концепция: sleep-check-sleep-check... и т.д. не будет ли это дополнительной нагрузкой на приложения на сервере при повсеместном использовании? ... Хотя, возможно внутри Co используется другой подход, т.к. в примере вижу, что асинхронная функция предварительно врапится, т.е. теперь вместо колбеков мы получаем другую боль в заднице - следить за проксированием асинхронных функций :)

Да и отлов ошибок через try-catch смущает, т.к. поведение JIT для кода внутри таких конструкций очень осторожно, а иногда и просто не применяется.

***

В общем я обязательно попробую Co в работе, чтобы на практике подтвердить или опровергнуть свои опасения :) Но пока я всецело за простые колбеки с роутерами, будь то промисы или ещё что, т.к. это просто наглядней, имхо :)

co(function *(){
  var a = yield get('http://google.com');
  var b = yield get('http://yahoo.com');
  var c = yield get('http://cloudup.com');
  console.log(a[0].statusCode);
  console.log(b[0].statusCode);
  console.log(c[0].statusCode);
})()


VS

async.map(['http://google.com', 'http://yahoo.com', 'http://cloudup.com'], get, (err, results) => {
    ...
});


Ну хз, мне второй вариант более по душе :)

melky 13.05.2014 10:17

Цитата:

Сообщение от kobezzza
т.к. это просто наглядней, имхо

да, я сейчас хотел написать функцию факториала на co.. в общем, мне нужна подготовка)


Часовой пояс GMT +3, время: 23:47.