Как вы пишете на сервере (node.js)
Много информации по написанию на node.js. Но чем больше ее изучаешь, тем понимаешь, что строгого подхода к написанию кода в node.js нет.
В этой теме хотелось бы понять при каких обстоятельствах использовать функции обратного вызова и события в node.js Когда-то можно и не прерывать процесс. Запросили данные, подождали, получили. Когда-то нужно с вызовом передать функцию обратного вызова (callback). И на другом конце обернуть ее process.nextTick() Наверное кто-то весь код "склеивает" событиями eventEmitter. Поделитесь опытом в каких случаях какие подходы задействуете. Спасибо! |
Главные правила ноды (из личного опыта, примерно ~ 2 года работы с нодой):
1) Не бросай исключений в асинхронных операциях, а передавай их как параметр callback; 2) Используй паттерны / фреймворки для работы с асинхронностью. Выбор фреймворка и паттерна зависит от предпочтений, я использую Async. 3) Нельзя по долгу занимать поток в серверном приложении, т.е. если нужно что-то большое посчитать, то либо используй setImmediate и дроби задачу, либо выноси задачу из Ноды на более предпочтительный инструмент (имхо, более правильное решение). Всё остальное уже не так важно, т.е. пиши как нравиться. |
Цитата:
|
Цитата:
Но на самом деле не важно на чём писать. Я обычно юзаю простую связку через REST, т.к. эту схему элементарно масштабировать и легко понять. |
kobezzza, а можешь дать пример кода, если не тяжело .
|
У тебя есть:
1) Кластер серверов на ноде, который принимает и агрегирует входящие запросы от клиентов; 2) Кластер серверов на Java/C++/Erlang и т.д., которые делают какие то жёсткие вычисления в 100500 потоков и т.д. Нужно организовать общение двух этих кластеров: берём банальный REST. В качестве транспорта можно взять тот же HTTP, организуем понятный для обоих сторон протокол и вуаля. Собственно по ссылке на википедии дан исчерпывающий ответ: Цитата:
|
Цитата:
спасибо. |
Цитата:
кстати, что ты имеешь в виду под "node.js" ? веб-сервер? так это ж только один компонент node.js наверное ты имел в виду express\connect :) я тоже долго допирал до того, как можно организовать код, чтобы вручную не прописывать route'инги, ибо это ну очень меня выматывает. решение оказалось простым - это было Цитата:
![]() я хочу сказать - ответ "везде, где есть ввод\вывод". но это я так думаю :) Цитата:
kobezzza, а почему стали делать именно так ? Цитата:
|
Цитата:
Или если рассматривать yield подход, то использование try-catch тоже не шибко нравиться, т.к. синтаксис конструкции слишком громоздкий и цена за её использование высока. Может я что-то не понимаю в этой жизни, но на мой взгяд это супер очевидно и удобно :) async.map(['file1', 'file2', 'file3'], fs.stat, function (err, results) { ... }); async.parallel( [ function () { ... }, function () { ... } ], function (err, results) { ... } ); Цитата:
А вот использование генераторов в других задачах я принял с восторгом и уже активно юзаю на сервере, собственно по этому я сейчас тружусь над новой версией Collection с поддержкой генераторов. |
Цитата:
try { setImmediate(function () { throw new Error('test error'); }); } catch (error) { console.log(error); //не поймает test error } |
Цитата:
|
Цитата:
Я понимаю для чего эти методы, но я не знаю где их применить Например 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 много, а в рабочем исполнении не находил. По статьям невозможно понять как это все вместе работает )) |
Цитата:
имею в виду процесс взаимодействия модулей между собой. Не обязательно express\connect Цитата:
|
Цитата:
Так или иначе, скоро в 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) { //произошла ошибка }); |
Цитата:
До вызова callback происходят некоторые расчеты, далее пауза и вызов callback уже в порядке следующего тика. |
Цитата:
зацени этот говнокод. рылся по истории 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); }); Цитата:
|
У меня самые частые - это 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) { ... } ); Цитата:
Дело в том, что при работа на сервере в ноде часто работа идёт с потоками, т.е. данные принимаются / отдаются чанками, что полностью противостоит модели промисов, когда данные получаются сразу. Делается это, как я уже говорил, из соображений эффективности. Так что какой-то революции нативные промисы не сделают, но всё же хорошо, что их добавят :) |
Цитата:
раньше такого термина не встречал, а теперь он появился, вместе с появлением оператора 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); }; } |
Цитата:
Цитата:
Да и отлов ошибок через 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) => { ... }); Ну хз, мне второй вариант более по душе :) |
Цитата:
|
Цитата:
co и Q.async на самом деле ничего сложного не делают, а просто автоматически выстраивают такую штуку:gen.next().value.then(function (value1) { gen.next(value1).value.then(function (value2) { gen.next(value2).value.then(function (value3) { gen.next(value3)... }); }) }); Вот рабочий пример для понимания: function asyncGet1(value) { return new Promise(function (resolve) { setImmediate(resolve, value); }); } function asyncGet2(value) { return new Promise(function (resolve) { setImmediate(resolve, value + 1); }); } function asyncGet3(value) { return new Promise(function (resolve) { setImmediate(resolve, value * 2); }); } function * genFunc() { var x = yield asyncGet1(1); console.log('x = ' + x); // x = 1 var y = yield asyncGet2(x); console.log('y = ' + y); // y = 2 var z = yield asyncGet3(y); console.log('z = ' + z); // z = 4 } //вместо co или Q.async: var gen = genFunc(); gen.next().value.then(function (x) { gen.next(x).value.then(function (y) { gen.next(y).value.then(function (z) { gen.next(z); }); }) }); yield никакой асинхронностью не занимается, он просто останавливает выполнение генератора до следующего вызова next .Когда пишешь генератор, можно представлять, что co в паре с yield разбивают genFunc на вот такие «подфункции»:function next1() { asyncGet1(1).then(next2); } function next2(value) { x = value; asyncGet2(x).then(next3); } function next3(value) { y = value; asyncGet3(y).then(next4); } function next4(value) { z = value; }Здесь специально расписал через value, чтобы воспринималось, как promise value. Кстати, в ES7 возможно будет реализация этого паттерна на уровне языка. Будут введены инструкции async (вместо co , Q.async ) и await (вместо yield ), и генераторы для это не нужны будут:async function func() { var x = await asyncGet1(1); var y = await asyncGet2(x); var z = await asyncGet3(y); } |
Цитата:
|
Цитата:
|
по мойму проще сервант на кокока завести, кокока куда лучше с js дружет
|
Цитата:
|
Цитата:
Цитата:
Цитата:
|
Цитата:
|
Цитата:
Цитата:
|
Цитата:
Цитата:
|
Цитата:
давненько хотел начать писать в функциональном стиле на JS в последний раз видел LiveScript, когда он только появился. он сейчас готов к продакшену? трудно ли начать писать на нём? выглядит страшновато |
c последовательной асинхронностью поступаю также как и dmitry111. Никакой пользы от async в этом моменте на практике не увидел.
когда нужно сделать несколько параллельных запроса тоже не умничаю. Просто отсчитываю количество. function X(options, end) { var J = 3; function complete() { if (--J !== 0) return; end(true); }; // ... process.nextTick(function () { complete(); }); process.nextTick(function () { complete(); }); process.nextTick(function () { complete(); }); } X({...}, function(status, data) { // ... }) |
Цитата:
Цитата:
Цитата:
|
Часовой пояс GMT +3, время: 19:54. |