Pull to refresh

Comments 32

Странно, что заикнулись про callback hell, но ни слова не сказали, про Promises. Тот же Bluebird.
К слову, node уже достаточно хорошо покрывает ES2015 без полифилов, в том числе и Promise: http://node.green/.
UFO just landed and posted this here
Так-то оно так, но я бы до сих пор рекомендовал использовать Bluebird.
Во-первых, у нативных промисов всё ещё есть некоторые проблемы, связанные со скоростью работы и занимаемой памятью.
Во-вторых, пока нативной поддержки API на промисах нет — без promisifyAll весьма тяжело.
Под громким заголовком «Вы не знаете Node» скрывается набор тривиальных фактов, щедро приправленный фактическими ошибками. Мде.

Кстати, а в чем разница между Apache 2.4 и nginx с точки зрения event loop, не расскажете?
Архитектурная, mpm не решает до конца проблемы С10K. У apache все же легаси. NginX изначально был event-driven и асинхронным. Так же у апача нет нормальных stream (upstream'ов — в терминах NginX).
> Начиная с версии 4.0 domain считается устаревшим, поэтому разработчики Node наверняка отделят его от платформы. Но на сегодняшний день в ядре Node нет альтернативы domain.

Только это не повод использовать устаревший модуль. К тому же, разве Promises не позволяют достаточно изящно обрабатывать асинхронные ошибки?
Статья не новая, но мне показалась достаточно интересная.
Да промисы позволяют решить проблему. Но, точно знаю, что есть кучу кода который написан в old-style, не известно будут ли там внедрены промисы или нет, да и возможно ли такое внедрение не сломав API — вопрос. По этому domain все же имеет право на жизнь.
Чтобы справиться с адом callback’ов, или пирамидой погибели (pyramid of doom), применяются эмиттеры событий. С их помощью можно реализовать асинхронный код с использованием событий.
nodejs.org/api/events.html#events_events
When the EventEmitter object emits an event, all of the Functions attached to that specific event are called synchronously.
То есть какой-то неправильный способ борьбы с callback hell предлагается, разве нет?
Почему же? Что мешает сделать асинхронные действия в invoked function? Или я вас не понял :)
Прошу прощения, разметку съел парсер почему-то.

Ничего не мешает сделать обработчики событий асинхронными, но в коде примеров в статье этого ведь не сделано.
Сказано что с помощью событий можно реализовать асинхронный код, а в примерах вместо этого написан синхронный (тут наверное уместно было бы подколоть автора что дескать сам не знает node.js — а все туда же :) )

Статья явно не первой свежести. Конструкторы Buffer получили статус deprecated. EventEmitter вовсе не способ борьбы с callback hell, это место прочно заняли Promise. А вместо console.error пора начинать использовать process.emitWarning.
Кто-то явно не знает Node.js, остается вопрос – кто?

Это статья не только про это, и что статья не новая было сказано. В ней есть много чего интересного, к примеру: как через pipe сделать chain of responsibility, явно не сказано но на мысли наводит; event drive…
А к деталям можно придраться в любом материале. ИМХО

Можно во всем искать только хорошее. Материал более чем на половину устарел или не соответствует действительности, а заголовок прямо указывает на обратное (отдает желтизной). Это может ввести новичков в заблуждение. Я бы на вашем месте сделал ремарку во вступительном абзаце, до того, как кто-то начнет применять эти советы на практике.

Хорошая мысль, добавил ремарку и ссылки на коменты.
1) Определенно в закладки
2) Если бы я был новичком и только-только открыл вашу статью, то уж точно ничего не понял бы. Статья вроде бы подразумевает, что читатели должны быть знакомы с Node, в то же время всё начинается весьма поверхностно, но не до конца разжевано. Например:

> Сравните Nginx и Apache. Именно благодаря циклу событий Node работает очень быстро
Читатель может быть не знаком с тем, что Nginx изначально асинхронный, а апач использует отдельные процессы. И далее сразу идет «именно поэтому Node работает очень быстро». Т.е. человек должен как-то сравнить два веб-сервера и прийти к выводу, что Node быстр. Что-то из разряда: «Сравните двс в Ладе и BMW. Именно поэтому самолеты такие быстрые!»

> Результат выполнения этого кода совершенно предсказуем даже для новичков в Node/JavaScript: data1->Hello Ruby->data2->Hello NODE!
Может я придираюсь, но прочитав ваш код — мне совершенно не очевидно, что там лежало в файлах, которые код должен был выдать. Там могло лежать «data1», а могла быть и «Война и мир»

И опять-же в следующем примере про асинхронное чтение файла — не факт, что первый файл прочитается быстрее, чем второй. Это зависит от FS и от размера файлов. Я думаю, это очень важно и про это стоит добавить, т.к. в этом и смысл callback'ов, что они могут вести себя весьма непредсказуемо — либо первый либо второй, зависит от разных причин. И это надо держать в голове.

Вроде примеры весьма простые, кажется что для новичков, но очень многое приходится додумывать, и будь на месте действительно новичок — ему будет многое непонятно. А для более-менее опытных — здесь мало нового. Я считаю, что если уж начали разжевывать, так разжуйте.

Как для читателя, соблазненным Node, но так и не освоившим на полную — подчеркну, что здесь приведен весьма интересный для меня материал. Однако столкнувшись с вашей статьёй на несколько лет раньше — не понял бы сути.

Еще вопрос:
Раскройте пожалуйста, что произойдет, если на один эмитер два раза повесить одно и то же событие 'knock':
emitter.on('knock', function(){})

Эмитер с вызовом функции срабоет дважды или единожды?
Согласен.
— Эмитер с вызовом функции срабоет дважды или единожды?
1-н раз сработает, вроде, он не chain'ит callback'и (2-а раза повесить не пробовал — вывод логический).
Если у вас что-то типа:
emitter.on('knock', aFun);
emitter.on('knock', bFun);
то при наступлении события knock будет вызваны, естественно, и слушатель aFun, и слушатель bFun (в порядке установки этих слушателей). Или вы о другом спрашивали?
TimsTims уточнил вопрос в лички, ага вопрос именно об этом :)
Для избавления от callback hell эвент-эммиттеры не сильно помогут, разве что – косвенно.

А вот настоящее счастье-радость наступает с использованием ES6-генераторов скрещённых с Promise: co.js

console.log('Hello');
co(function* () {
  let data1 = yield asyncCall1(); // wait for async call
  console.log(data1);

  let data2 = yield asyncCall2(); // wait for async call
  console.log(data2);
});
console.log('World!');

Выведет следующее:
Hello
World!
[data1]
[data2]

Причём, data1 и data2 будут строго в этом порядке.
Если честно, «co» нужен только как временная альтернатива пока нет нативного async/await.
Причём остался ли он нужен сегодня, когда Babel переводит вам код с async/await в код на генераторах — тоже вопрос.
Я не говорю, что «co» плохой или что его не надо использовать, но я сомневаюсь, что это то, с чего надо сейчас начинать.
Есть ненулевой шанс, что его задепрекейтят в ближайший год.
> Аддоны на C++

Хочется поделиться ссылкой на проект который может оказаться весьма полезным для желающих написать свой С++ Addon для Node.js (впрочем как и для NW.js и Electron): cmake-js — данный проект позволяет использовать CMake в качестве системы сборки вместо node-gyp. Проблема в том что для большинства сторонних библиотек .gyp файлы придется писать самостоятельно (а зачем еще может понадобиться написание C/C++ addon кроме как для подключения сторонней библиотеки?), в то время как с CMake шансы избавить себя от дополнительной работы весьма высоки.

Ну а если у вас все же возникнут проблемы в этом вопросе, то как говориться «Хочешь написать node.js addon — спроси меня как». Мне волей не волей пришлось съесть собаку на этой теме :)
Прикольная тулзовина!
— (а зачем еще может понадобиться написание C/C++ addon кроме как для подключения сторонней библиотеки?)
Для оптимизации некоторых build-in функций — бывало такое ;)
возможно вы этом случае было правильней слать патч разрабочикам Node.js, но в общем то согласен, такой вариант тоже имеет место быть.
UFO just landed and posted this here
Какие типы мы можем использовать для бинарных данных? Если помните, в браузере JavaScript нет бинарного типа данных, а в Node есть. Это называется буфером.
В браузерах появился TypedArray (ES2015). В последних версиях Node «Buffer» является классом над стандартным Uint8Array API.
А вы точно «знаете Node.js»?

По пунктам:

> К слову, в Node.js всё же можно написать блокирующий код.

Вы это подаёте так: «в Node.js по умолчанию всё асинхронное, но можно использовать *Sync методы и будет как вы привыкли», не упоминая про то, что использование синхронных методов на сервере в процессе работы — выстрел себе в ноги из гранатомёта. В первую очередь в статье для новичков стоило бы на этом акцентировать внимание, а то пойдут же *Sync вызовы втыкать.

> Чтобы справиться с адом callback’ов, или пирамидой погибели (pyramid of doom), применяются эмиттеры событий.

Как уже сказали — Promises, async/await. Не надо городить ад на эмиттерах =).

> Буферы

Очень важный момент (не упомянутый в этой статье) — Buffer(number) фактически выделяет кусок памяти, в которым могут быть чувствительные данные. Именно поэтому в новой версии его разделили на Buffer.from(val) и Buffer.alloc(number)/Buffer.allocUnsafe(number) — чтобы случайно не вызвать Buffer(number) при передаче числа там, где предполагался вызов Buffer(val). Buffer.alloc(number), кстати, теперь зануляет выделяемую память (allocUnsafe — нет, но его стоит использовать очень осторожно).

> Где хранить пароли?
> Для этого существует глобальный объект,

Нет, глобальный объект существует не для этого. Вынесите ваш конфиг в модуль/файл.

> global.__filename, global.__dirname, global.module, global.require

Они все — undefined, в вашей статье ошибка.
Эти переменные определяются не на глобальном объекте, а как аргументы функции-обёртки require.

> pm2

В прошлый раз, когда я про это упоминал, местной аудитории это очень не понравилось (вплоть до ограничения на комментирование), но я всё равно повторю: не стоит думать, что pm2/forever в вакууме — надёжный способ перезапуска приложения в продакшне. Чтобы гарантировать перезапуск, надо построить цепочку ватчеров вплоть до системного инита (и до аппаратного watchdog), и никак иначе. pm2/forever тоже могут упасть (и делают это). А если вы используете pm2/forever _исключительно_ для перезапуска — тогда он вам вообще не нужен, скорее всего.

> uncaughtException

Ещё стоит упомянуть unhandledRejection.

> Обработка асинхронных ошибок
> Прослушиваем uncaughtException.

Нет, единственное, что стоит делать при возникновении uncaughtException — закрывать всё и завершать процесс, вы же сами это упоминали.
А для красивой обработки асинхронных ошибок есть Promises, можно в сочетании с async/await.

> Аддоны на C++

Первое, на что стоит смотреть для написания нативных аддонов — nan. Если вы будете дёргать v8 руками — пострадает совместимость с версиями Node.js, и при обновлении вам с большей вероятностью придётся что-то переписывать. nan берёт это на себя.
>Противники Node часто приводят аргумент, что он <?> может масштабироваться
Не пропала ли здесь частица НЕ?

Вот после этого в коде примера ошибка:


Синтаксис fork() почти аналогичен синтаксису метода spawn(), за одним исключением: здесь не нужна команда, потому что fork() предполагает, что все процессы относятся к Node.js:

var fs = require('fs')
var process = require('child_process')
var p = process.fork('program.js')
p.stdout.on('data', function(data)) {
  console.log('stdout: ' + data)
})

У потомка stdout и stderr равны null, и код выдаст ошибку:


TypeError: Cannot read property 'on' of null

Sign up to leave a comment.