Pull to refresh

Comments 72

Интересный ответ вместо 'Not Found' выдаёт на скриншоте http.STATUS_CODE для кода 404, видимо это собственное изобретение автора.

P.S. увидел, что перевод, исправил.

Даже, если из всей статьи оставить только пункт 2, то эта статья не потеряет ценности. Потому что это просто неописуемо круто, когда можно дебажить удаленный проект так просто. В браузере.

В чем неожиданность то? В том что документацию хорошо бы хотя бы читать?
UFO just landed and posted this here

Вы серьезно? Как вообще можно разрабатывать под какую-нибудь платформу, не зная документации? Я считаю, что это статься не достойна главной, так как тут ничего нового для среднего разработчика Node.js не найти
Документация Node.js очень маленькая и простая, потому что Node.js по сути обретка над различными библиотеками, в отличии от PHP, Ruby, Python и других языков, где стандартные библиотеки богаты различными интересными штуками, о которых в документации если и есть что-то, то это нужно хорошенько поискать

UFO just landed and posted this here
мне кажется, такой стиль программирования погубил flash.
потому что, платформа отличная, но низкий порог вхождения все испортил.
Flash тоже не святой. столько нервов отнял не только у web-мастеров, но и у пользователей.
В смерти flash вините соцсети. Сколько раз из-за него только мой системник вырубался от перегрева.
Еще помню как со злости проломил динамик в microlab pro 1 (правда, мне было не жалко, они все равно хрипели).
У меня была дискуссия с руководителем — кем является программист, творцом или ремесленником.
Вы убедили меня в том что некоторые — все таки ремесленники. Открыть мануал, повторить что написано, скомпоновать по своему — это обычный «кодинг», и даже в этом случае нет гарантий что вы давным давно прочитав описание неких методов — запомнили это и теперь используете. Вероятнее — вы помните что читали, и не читаете повторно, но забыли о чем и не используете.
Ведь согласитесь вы не перечитываете мануалы при апдейтах? А ведь алгоритм встроенных методом мог изменится, и тот что вы не использовали ранее из-за тормозов, стал оптимальнее текущих ваших приемов.

Буквально вчера читал даже не описание, а подсказку к настройке плагина Atlassian, где написано «в данной версии умеем присваивать только цифры и текст». Они не указали «списки выбора», и если бы я поверил — то не стал бы использовать для присвоения enumeration, которые внутри все таки цифры, но пойди их еще найди.
querystring сконвертит все что найдет в строках urlencoded. Сомнительный хак.
process.on('uncaughtException', console.error);

Не делайте так. Тем более для «предотвращения остановок сервера».


Ссылка на доку: https://nodejs.org/dist/latest-v7.x/docs/api/process.html#process_event_uncaughtexception


конечно, нахожусь в здравом уме, поэтому пользуюсь PM2

PM2 в вакууме тоже не является гарантией того, что всё это не упадёт. В продакшне надо использовать системные менеджеры для запуска всего, независимо от наличия PM2 (который может использоваться для других целей).


у объектов EventEmitter имеется и метод code

code? Это ошибка?

В продакшне надо использовать системные менеджеры для запуска всего

Можно подробнее? Что это за менеджеры?

На совеременных Linux-дистрибутивах это systemd, см. http://0pointer.de/blog/projects/watchdog.html.
На более старой убунте и ещё нескольких дистрибутивах это upstart.
На чём-то ещё — другие системные средства, которые гарантируют работу сервисов.


Полагаться на то, что запущенный без какого-либо надсмотрщика pm2/forever/чтоещё сам не упадёт — довольно безумно в продакшне.

PM2 в последних релизах сделал интеграцию с systemd/upstart, так что теперь чуточку удобнее.

Ага, спасибо, я взгляну на это чуть позже, интересно, как это реализовано и поддерживают ли они watchdog.


Когда я последний раз смотрел, у pm2 была целая куча жалоб в issues где пользователи запускали его в отрыве от всего а потом ловили внезапный oom, который убивал pm2 и очень удивлялись.


По-хорошему, таким утилитам нужна не только опциональная поддержка интеграции, но ещё и активное напоминание о том, что её всё-таки стоит включить (если его там ещё нет).


Сейчас у меня довольно плохо всё со временем, но я себе записал в список дел посмотреть на то, как именно в pm2 организовали интеграцию с systemd/upstart и прокомментировать, если я замечу в этом косяки.

Касательно п.5: будьте осторожны, без __dirname иногда не обойтись, например, когда ваш компонент подключается как npm-модуль, в данном случае require справится, а вот fs.readFile — нет (старый добрый ENOENT).
Практически везде, кроме require, относительный путь берётся от директории запуска.
Если вы запускается скрипт из /~ или C:\ то все пути fs.readFile('./...') будут идти от этой директории, в то время как в require путь берётся от файла, где он вызван.
На текущую директорию в серверном приложении вообще полагаться нельзя (разве что если вы временные файлы создаете, да и для тех tmpfs есть). Она зависит от того, какой командой и каким обработчиком запускается приложение, и совершенно не факт, что она совпадет с директорией, в которой лежат ваши файлы.В зависимости от фантазии админа это можент быть как ~ или /root/, так и /etc/cron.d/ или F:/MUSTDIE.
UFO just landed and posted this here

В смысле — пропадает? Покажите конкретную последовательность команд, пожалуйста.

Если сделать просто «require('lodash')», но не присвоить присвоить результат «require('lodash')» в явном виде той переменной, имя которой состоит из знака подчёркивания (такое имя переменной чаще всего и используется пользователями lodash), то тогда этот результат присвоится этой переменной автоматически, но не менее автоматически пропадёт (то есть переменная эта переприсвоится) на следующем же шаге REPL — оттого, что в REPL переменная с таким именем имеет особый смысл, что также сказано в документации Node.js.
Заголовок обещал неожиданные находки, а статья об очевидных вещах, о которых автор не знал т.к. не читал документацию.

Я помню как один раз у нас в документации <<<<<<< HEAD нашёлся, вот это было неожиданно.


Но с тех пор добавилась проверка на них на этапе линта на CI.

Я запускаю проект так:
NODE_PATH=. node app.js
и все модули ищутся относительно текущей директории. Соответсвенно в продакшне используется pm2 и для него создается список процессов processes.json, где также задается эта переменная окружения.

Не совсем понял, как это относится к моему комментарию выше, но ладно.


Так же я не понял, зачем вам нужен NODE_PATH, и почему вы не кладёте зависимости в папку приложения.
Лучше всего NODE_PATH не пользоваться вообще и забыть про него, он оставлен для совместимости.

Переопределение NODE_PATH на корень своего проекта — совсем не тру-практика.
Здравым смыслом подразумевается, что в переменной NODE_PATH хранится корень установленного NodeJS.
Здравым смыслом подразумевается, что в переменной NODE_PATH хранится корень установленного NodeJS.

Если честно, я не понял мысли. Можете показать на примере путей, что вы имеете ввиду?


К слову о «тру-практиках» — использование NODE_PATH вообще не рекомендовано.

По умолчанию при установке NodeJS переменная NODE_PATH не задается в окружение. Оставить ее пустой или незаданной гораздо лучше, чем использовать не по назначению. Я могу и ошибаться. Но настраивать NODE_PATH в корень одного проекта — это может быть уместно если на одной машине один проект и, соответственно, запускается один app.js.

В любом случае, вопрос развертывания к сисадмину. Разрабатывать на локальной машине проекты можно так, как удобно разработчику.
Скорее всего, по поводу тру- или нетру- практики я перегнул палку. Тут нет однозначного ответа. В продакшене, обычно переменные, именуемые КАПСом у меня имеют одно значение для всех скриптов, заданное в profile при загрузки ОС. Тут Node не одинок. Среди переменных есть GOPATH, ROR_PATH…
Вещи, может, очевидные, а статья полезная, т.к. не всегда вдумываешься в то, что написано. Смотришь только на параметры. К примеру, я привык на PHP к тому, что array_slice возвращает часть массива, и эту часть можно изменять. А в Node.js нельзя изменять часть буфера, если не нужно менять оригинал.
Buffer это не Array, и работает по другому и для других целей
Он даже создается таким образом, чтобы показать что тут память вылеляется, а не типичный объект создается
const buf1 = Buffer.alloc(10);

И нужно с понимать что вы делаете

Для всего остального все работает как и ожидается

let arr = [0, 1, 2, 3]
let arr2 = arr.slice(1)
// arr2 новый массив, изменяя который первый не будет изменен

let str = "abcdef"
let str2 = str.slice(1, -1)
// str2 новая строка, независимая от первой

//Если вам нужна просто копия всего, можно сделать
let copyArr = arr.slice()
Раз речь зашла о системных мелочах Node.js.

Хотел бы спросить.
Может уже придумали решение чтобы не делать require('../../../../moduleA') внутри moduleB?
Ограничение «только относительные пути» ухудшает читабельность и рефакторинг.
Насчет упаковки включаемого кода в node_modules в курсе — не выход (неудобно).
Я правильно понял, что у вас есть файл moduleB.js и из него вы хотите подключить файл, расположенный по отношению к нему по пути ../../../../moduleA.js и чтобы было как-то типа require(«moduleA»)?
Я что-то такое делал, сейчас поищу.
Можно добавить в module.paths путей папок, в которых будет искаться модуль. Выведите в консоль, что у Вас содержится в этом свойстве и сможете придумать какую логику над этим надо провернуть.
Значение module.paths вычисляемое и различается для модулей в разных каталогах…

Вообще require поддерживает абсолютные пути, но относительно корня текущего диска.
Может быть стоит где-нить в main.js кроссплатформенно вычислить абсолютный путь до корня проекта.
Записать его в глоб. переменную (одна переменная — терпимо) и дальше везде тупо собирать полный путь…
Путь вида «корень-проекта/node_modules» наверняка уже содержится в module.paths. Опознать его и обрезать node_modules, я думаю, не слишком сложно.
Кажется, хватит тупого сохранения значения __dirname в main.js.

Прокатит даже для клиентского js-кода где за require-кухню отвечает webpack.
Только придется поддержку __dirname ему в конфиге включить явно.
итого, в точке входа в корне проекта пишу
global.path = require('path');
global.root = __dirname;


инклуды в других файлах, было:
var module = require('../../../../moduleA');


стало:
var module = require(path.resolve(root, 'controller/net/moduleA'));


проверил на Win\Mac — нормально
Я писал маленькую статейку про костыль решающий бардак путей к модулям. Только она старая, для бородатых версий node. Возможно, уже есть решения полаконичнее.

А зачем засорять global? Можно и так:


var module = require(path.resolve(process.cwd(), 'controller/net/moduleA'));
+можно упростить — вместо path экспортировать сразу path.resolve =)
Да, верно… Для разового включения это терпимо.
Но допустим, этот moduleA.js включен много где в файлах расположенных разных по уровню каталогах.
Каждый раз приходится «спускаться» до корня проекта вручную, потом «подниматься» до модуля.

Либо задумываться о замене CommonJS-вского require на что-то более умное.
Либо делать костыли — заранее в main.js подключить всё и сделать глобальным (с неймспейсами если надо):
global.ModuleA = require('./moduleA.js')
Можно создать свой модуль и экспортировать его.

	var Module = module.constructor;
	var m = new Module('');
handle(m.paths); //Внесли нужные правки

module.exports = m;


Использовать потом — m.require

Или можно покопаться в process.mainModule.paths, а потом использовать process.mainModule.require

UPD,
Да, почему бы не положить где-то в более удобном месте
module.exports = require('../../../../moduleA')?

1) Посмотрите на NODE_PATH


2) Но вообще, если у вас есть такие длинные пути в require, то почему бы просто не перенести зависимые модули в папки поближе друг другу?

1) Вариант если пути к модулям неизменны и их мало. Слово «модуль» в контексте «файл с js-кодом».
2) Вариант если нет фреймворка или иерархии компонент в сочетании например с Redux

Впрочем, пока для себя определился.
>Может уже придумали решение чтобы не делать require('../../../../moduleA') внутри moduleB?

можно начать собирать webpack-ом, там резолвинг настраивается. А можно начать использовать typescript — module resolution. В общем инстументы есть.
А webpack для сервера зачем? Пост про ноду…

Чтобы собрать модули по своей кастомной логике, если не устраивает стандартная нодовская.

Спасибо за инфу про резолвинг! Проверил, на клиенте вопрос с путями в require решен без костылей.
UFO just landed and posted this here
можете по п5 подробнее?
с остальным согласен более чем полностью!
Относительные пути работают не только с модулем fs.Тут все гораздо более глобально. Это относится не столько к NodeJS, сколько к основам принципов работы операционных систем.
UFO just landed and posted this here
Модуль net вдвое быстрее модуля http


Спорное утверждение. Это как сравнивать теплое с мягким. Я бы утверждал что скорость их работы при заданных условиях работы приблизительно одинаковая.

В результате http.Server смог обработать примерно 3400 запросов в секунду, а net.Server – примерно 5500. К тому же, net.Server проще устроен.


Ваша статистическое утверждение никак не может быть объективным. Во-первых, вы пренебрегаете keep-alive-соединениями. Во-вторых, количеством одновременных соединений.

Конечно же, используя net можно написать реализацию любого протокола. Но, в большинстве случаев отладка своего протокола может превратиться в ад. Для большинства случаев подходит простенький и экстремально быстрый пакет ws, основанный на WebSocket. Удобно это прежде всего тем, что двухсторонний обмен данными происходит сообщениями из js-объектов. Это позволяет не заморочиваться с проектированием протокола обмена, можно добавлять и удалять параметры в сообщения и их обработку в любой момент разработки, что повысит гибкость работы с версиями API. Также, если не ошибаюсь, через объект этого сообщения можно передавать функции, содержащие произвольный js-код. Ну, и нельзя отметать возможность отлаживать взаимодействие с помощью браузера.
Хочется также поздравить автора с эволюционированием скилла разработчика до продвинутого разработчика.
Внимательное изучение API-документации используемых средств разработки происходит далеко не в самом начале карьеры.
Следующий этап развития разработчика (назовем его, например, гуру разработчик) происходит, когда разработчик изучает используемые средства по исходным кодам этих средств.
Тут я серьезно! Когда все API-документации средств изучены, тяга к познаниям обязательно заставит изучать используемые в разработке средства по исходным кодам.
Внимательное изучение API-документации используемых средств разработки происходит далеко не в самом начале карьеры.

А я изучал на первом курсе справочную и методологическую часть API платформ по книгам, начиная со второго-третьего — с официальных документаций API, с третьего-четвертого — с исходных кодов.
С тех пор придерживаюсь этого стиля.
При изучении новых платформ/новых версий давно знаю, какие ключевые точки посмотреть для изучения — для быстрого входа в разработку, далее смотрю документацию итеративно, +ресурсы типа забра помогают.

И надо сказать, что зная точно, какую часть API для каких задач и как именно использовать, тяжело смотреть на код коллег, «кодящих» по подсказкам IntelliSense — такой подход часто приводит к использованию методов не так, как они предназначены для решения задачи (отличия могут быть в параметрах, обработке исключений), к использованию неподходящего метода, к использованию методов, ставших Obsolete N версий назад, или и вообще к своему велосипедному коду, в то время, когда в платформе с версии 1.0 есть стандартные методы для решения задачи.

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

В свое время столкнулся с реальным случаем, когда в продукте, развивавшимся 10 лет, разработчики сталкивались с падениями OutOfMemory exception, т.к. в своем велосипедном ORM кодировали запросах BLOB'ы в виде шестнадцатеричном текстовом виде.
Т.е., за 10 лет никто не открыл ни одной книжки, ни официальной справки (офлайновая в IDE, веб на официальном сайте), и не узнал, что параметризованные SQL запросы существовали в платформе с версии 1.0
(тем более не говорю про возможность потокового чтения-записи блоб'ов в БД).
В добавление к п.2 хочется отметить наличие readline-интерфейса. Тоже неплохая альтернатива отладки без использования браузера.
Посмотрел в документацию и сам чуть не поседел. Столько всего нового, что вообще не понятно, что я имел в виду, когда писал комментарий выше.

NodeJS. как и многие другие инструментальные средства по Unix-традициям запускается тремя способами:
  1. путь к файлу скрипта предается параметром node script.js;
  2. скрипт передается процессу node через стандартный поток ввода cat script.js | node;
  3. или просто вручную запускаем node без параметров node.


Ручной запуск ноды без параметров инициализирует readline-интерфейс. Здесь нода будет выполнять скрипт по-строчно с теми же возможностями, как и в консоли браузера.

Главный файл проекта можно подключить параметром запуска --require или функцией require() или даже import. А после подключения главного модуля, сервер или что там подключали работает, а во время выполнения этого процесса можно его отлаживать, например, проверяя значения переменных или вручную вызывая различные функции, влияющие на состояние процесса.
Возможно вы заметили, что в примерах я использую для строк одинарные кавычки.

Вообще-то «backticks» — это обратные кавычки. Одинарные — это «single quotes» (')

Вот дела, а я сам и не заметил сразу).

Ничего не имею против es6-шаблонов, определенных таким образом. Но использовать их вместо статических строк не рационально. Автору советую лучше протестировать производительность шаблонов и статических строк. Интересно, как помогает автору pm2 в отладке?! Автор, какие средства используете для борьбы с утечками?
Интересно, как помогает автору pm2 в отладке?! Автор, какие средства используете для борьбы с утечками?

Автора в этой теме нет, вы говорите с переводом на русский язык, размещённом в блоге хостера VDS/VPS.

<зануда mode>
Backticks — это все-таки апострофы, а не одинарные кавычки.
</зануда mode>
Странно сравнивать производительность net и http, учитывая, что второй должен не просто данные собрать, но и http распарсить.
Если я ничего не путают http использует net внутри для собственно работы с сетью.
И я так и не понял, почему 5500/3400 — это "вдвое быстрее".

Исправлено. Спасибо за замечание.
node --inspect — то чего так не хватало. Спасибо огромное от всей души.
Тут выше писали о том, что backtick — это не просто одинарная кавычка. Вставлю свои 5 копеек по поводу удобства использования именно ` вместо " и '. Можно делать вот так:
let a = 10;
let b = 15;
console.log(`Сумма: ${a+b}`); // Выведет Сумма: 25
// Внутрь ${} можно подставлять любое js-выражение
var str = `Логарифм: ${Math.log(10)}`); 
//str == 'Логарифм: 2.302585092994046'

Очень удобный способ форматирования строк, на мой взгляд.
Поправьте пожалуйста пункт 5:
__dirname не имеет отношение к cwd, __dirname — это путь к папке с файлом, в котором она написана.

scripts/test.js
console.log(__dirname)


$ node scripts/test.js 
/path/to/your/project/scripts


Такие ошибки запутывают новичков и приучают работать с абсолютными путями)))))
require(`net`).isIP(`cats`)

Возможно вы заметили, что в примерах я использую для строк одинарные кавычки.

Мы заметили, что вы используете не одинарные кавычки, а обратные апострофы.
Было бы оправдано, если бы вы использовали шаблоны:


require('net').isIP(`${ myPet }s`)

но вы ведь нет, так что зачем?

Про одинарные кавычки, это ошибка переводчика, в оригинале было backticks.


Зачем их использовать даже вне шаблонов? Для единообразия, иногда это удобно, что абсолютно все строки оформляются одинаковыми значками. Вот тут есть больше слов об этом.

Sign up to leave a comment.