Node – фантастическая платформа для написания бэкэндов. За исключением случаев, когда вы не понимаете все правильно.


В зависимости от того, на какой стороне вы находитесь, Node – лучшее или худшее, что может случиться в мире веб-разработки. Но, несмотря на мнения, о популярности Node не спорят. Он взлетел в популярности намного быстрее, чем кто-либо ожидал, даже его создатель (он сказал так с другой стороны, пессимистично интервью)!

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

К сожалению, дошло до того, что когда кто-то просит меня порекомендовать им стартовый стек для веб-разработки или новых продуктов для запуска, Node – моя рекомендация № 1, хотя я хорошо разбираюсь в PHP и Laravel..

Если мне будет позволено немного продолжить разглагольствование (чем я буду заниматься, поскольку я пишу один?), У ненавистников Node есть момент, когда они говорят, что их любимый веб-стек может делать вещи так же, как Node, но Обратное также верно. И затем есть вещи асинхронного программирования и события, которые были запечены в Node с первого дня, и другие экосистемы теперь отчаянно пытаются копировать.

Сегодня у нас есть опции асинхронности в PHP и Python, но, к сожалению, ядро ​​существующих, популярных библиотек является чисто синхронным, так что вы почти боретесь с системой. Но все равно хватит разглагольствовать на день. ��

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

Не уважая цикл событий

Когда человек мигрирует на Node, это происходит отчасти потому, что он слышал истории о том, как LinkedIn масштабируется с использованием Node, или он видел тесты, показывающие, как Node работает по кругу вокруг PHP, Ruby и т. Д., Когда речь идет об обслуживании запросов в секунду или обработке открытые разъемы.

Таким образом, они создают свое приложение, ожидая того же самого взрывного времени отклика, о котором они мечтали – за исключением того, что ничего подобного не происходит.

Одна из главных причин этого – неправильное понимание цикла событий. Рассмотрим следующий код, который получает набор книг из базы данных, а затем сортирует их по общему количеству страниц:

db.Library.get (libraryId, function (err, library) {
let books = library.books;
books.sort (function (a, b) {
вернуть страницы < б.страницы? -1: 1
});
});

Я согласен, что этот код ничего не делает с массивом отсортированных книг, но здесь дело не в этом. Дело в том, что такого невинно выглядящего кода достаточно, чтобы взорвать цикл событий, как только вы начинаете работать с нетривиальным количеством книг..

Причина в том, что цикл обработки событий предназначен для выполнения неблокирующего ввода-вывода. Хороший пример – упаковщик пиццы в пиццерии – человек специализируется на разрезании пиццы, складывании крышек в коробки для доставки, помещении пиццы, прикреплении правильных этикеток и доставке ее доставщику.

Удивительно, правда? Так же, как узел!

Источник: stackoverflow.com

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

Это то, что мы подразумеваем под задачами, которые «блокируют» – если Node просто должен передавать информацию, это очень быстро и в идеале лучший вариант, но как только ему нужно сделать обширные вычисления, он останавливается и все остальное должно подождать. Это происходит потому, что цикл обработки событий является однопоточным (подробнее Вот.)

Поэтому не выполняйте вычисления в цикле событий, независимо от того, насколько они важны. Я имею в виду, что сложение чисел и получение средних значений – это хорошо, но большие наборы данных заставят ваше приложение Node сканировать.

Надеемся, что асинхронный код будет сотрудничать

Рассмотрим очень простой пример Node, который читает данные из файла и отображает их:

const fs = require (‘fs’);

let contents = fs.readFile (‘secret.txt’, (err, data) => {
вернуть данные;
});

console.log (‘Содержимое файла:’);
console.log (содержание);

Экспонирование к классическим языкам (таким как PHP, Python, Perl, Ruby, C ++ и т. Д.) Заставит вас придерживаться здравого смысла, что после выполнения этого кода содержимое переменной будет иметь содержимое файла. Но вот что происходит, когда вы фактически выполняете код:

Мы получаем undefined (). Это потому, что, хотя вы можете глубоко заботиться об Node, его асинхронная природа не заботится о вас (это должно быть шуткой! Пожалуйста, не спамите здесь комментарии ненависти ��). Наша задача – понять его асинхронный характер и работать с ним. readFile () – это асинхронная функция, которая означает, что при ее вызове цикл обработки событий Node передает работу компоненту файловой системы и переходит к.

Он вернется к функции позже, когда файл будет прочитан, но к тому времени содержимое обрабатывается как неинициализированная переменная и, таким образом, содержит неопределенное значение. Правильный способ – обработать данные файла внутри функции обратного вызова, но я не могу вдаваться в подробности, так как это не Узел учебник. ��

Обратный вызов, который вызывает обратный вызов, который вызывает обратный вызов, который вызывает . . .

JavaScript ближе к функциональному программированию, чем любой другой более старый, общепринятый язык (на самом деле все сказано и сделано, он мой любимый, когда речь идет об объектно-ориентированном дизайне и функциональных возможностях – я ставлю его выше Python, PHP, Perl, Java и даже Ruby, когда речь идет о написании «приятного» кода).

То есть функции получают больше гражданских прав, чем на других языках. Соедините это с тем фактом, что асинхронный код работает, предоставив вам функцию обратного вызова, и мы в итоге получим рецепт катастрофы, известный как Callback Hell.

Вот пример электронного кода, с которым я столкнулся на Quora. Как вы думаете, что это делает?

варианты вар;

требуется ( ‘электрон’). app.once (
‘готов’,

function () {

варианты = {
кадр: ложь,
высота: 768,
ширина: 1024,
х: 0,
у: 0
};

options.BrowserWindow = требуется («электрон»). BrowserWindow;
options.browserWindow = новые параметры.BrowserWindow (options);
options.browserWindow.loadURL ( ‘http://electron.atom.io’);
options.browserWindow.webContents.once (
«Сделал стоп-погрузка»,

function () {
options.browserWindow.capturePage (
опции,

функция (данные) {
требуется ( ‘фс’). writeFileSync (
‘/Tmp/screenCapture.testExampleJs.browser..png’,
data.toPng ()
);

process.exit (0);
}
);
}
);
}
);

Если вам трудно, вступайте в клуб!

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

Есть много способов избежать ада обратного вызова, в том числе обещания а также Реактивные расширения.

Не использует все ядра процессора

Современные процессоры имеют несколько ядер – 2, 4, 8, 16, 32. , , число продолжает расти.

Но это не то, что имел в виду создатель Node, когда выпускал Node. В результате Node является однопоточным, что означает, что он работает внутри одного потока (или процесса, если вы хотите его так называть, хотя они не совпадают), используя только одно ядро ​​ЦП..

Это означает, что если вы изучили Node из учебных пособий, с друзьями и фрагментами кода, а ваше приложение развернуто на 8-ядерном сервере, вы тратите 7/8 доступной вычислительной мощности.!

Излишне говорить, что это огромная трата. Если вы пойдете по этому пути, вы в конечном итоге заплатите за восемь серверов, когда вам нужен только один. То есть тратить 16 000 долларов в месяц, когда будет делать 2 000 долларов (потеря денег всегда вредит, верно?). Все это, когда решение довольно простое: использование кластер модуль.

Я не могу вдаваться во все детали здесь, но это простой метод определения количества ядер на текущей машине и запуска такого количества экземпляров Node. При обнаружении ошибок экземпляр перезапускается. Вот как это просто реализовать (учебник Вот):

var cluster = require (‘cluster’);

if (cluster.isMaster) {
var numWorkers = require (‘os’). cpus (). length;

console.log («Настройка главного кластера» + numWorkers + «рабочие …»);

для (var i = 0; i < numWorkers; я ++) {
cluster.fork ();
}

cluster.on (‘онлайн’, функция (работник) {
console.log («Рабочий» + worker.process.pid + «онлайн»);
});

cluster.on (‘выход’, функция (работник, код, сигнал) {
console.log (‘Worker’ + worker.process.pid + ‘умер с кодом:’ + code + ‘и signal:’ + signal);
console.log («Начиная нового работника»);
cluster.fork ();
});
} еще {
var app = require (‘express’) ();
app.all (‘/ *’, function (req, res) {res.send (‘process’ + process.pid + ‘говорит привет!’). end ();})

var server = app.listen (8000, function () {
console.log («Process» + process.pid + «прослушивает все входящие запросы»);
});
}

Как вы можете видеть, cluster.fork () делает магию, а остальные просто слушают пару важных событий кластера и выполняют необходимую очистку.

Не использует TypeScript

Хорошо, это не ошибка как таковая, и множество приложений Node были и пишутся без TypeScript.

Тем не менее, TypeScript предлагает гарантии и душевное спокойствие, которые всегда нужны Node, и, на мой взгляд, это ошибка, если вы разрабатываете для Node в 2019 году и не используете TypeScript (особенно когда A (Angular) в стеке MEAN перемещен на TypeScript давно).

Переход плавный, и TypeScript почти точно похож на JavaScript, который вы знаете, с гарантией типов, ES6 и несколькими другими проверками:

// /lib/controllers/crmController.ts
импорт * как мангуст из «мангуста»;
импортировать {ContactSchema} из ‘../models/crmModel’;
import {Request, Response} из ‘express’;

const Contact = mongoose.model («Контакт», ContactSchema);
класс экспорта ContactController {

public addNewContact (req: Request, res: Response) {
let newContact = new Contact (req.body);

newContact.save ((ошибка, контакт) => {
если (ERR) {
res.send (ERR);
}
res.json (контакт);
});
}

Я бы порекомендовал проверить это приятно и дружелюбно Учебник по TypeScript.

Вывод

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

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

Jeffrey Wilson Administrator
Sorry! The Author has not filled his profile.
follow me