Содержание
- Необрабатываемые исключения в потоках
- Прикрепить обработчики событий ошибок
- Использование метода конвейера
- Используйте функцию finished()
- Ошибка Куча памяти в JavaScript
- Незакрытые соединения
- Неразмещенные объекты
- Циклические ссылки
- Большие приложения
- Ошибки совместимости с окружением
- ReferenceError: window is not defined
- ReferenceError: XMLHttp Request is не определено
- Сетевые и коммуникационные ошибки
- Ошибка: чтение ECONNRESET
- Ошибка: соединение ECONNREFUSED
- Ошибка: listen EADDRINUSE: адрес уже используется
- Ошибка: запись EPIPE
- Дополнительные распространенные ошибки Node.js
- .find не является функцией
- TypeError: arr.find не является функцией
- Uncaught SyntaxError: Неожиданный идентификатор
- Заключение
Ошибки могут стать серьезной проблемой для разработчиков, часто приводя к ненужным затратам времени. Мы можем быстро указать пальцем на язык программирования или среду, но справедливо будет признать, что многие из этих ошибок являются следствием ошибок разработчиков и того, как мы используем эти инструменты.
Node.js существует уже довольно давно и сыграл важную роль в создании надежных и сложных веб-сервисов, которые эффективно масштабируются и выдерживают испытание временем. Но, как и любая другая среда исполнения или платформа, Node.js подвержена ошибкам разработчиков.
В этой статье мы рассмотрим некоторые из наиболее распространенных ошибок Node.js, с которыми вы можете столкнуться, и обсудим, как их исправить.
Необрабатываемые исключения в потоках
Потоки - это фундаментальная концепция в Node.js для чтения и записи в асинхронные источники данных, такие как файлы, сокеты или HTTP-запросы. Ошибки могут возникать в любое время в течение жизненного цикла потока.
Потоки выдают ошибки во время различных операций, таких как чтение, запись, конвейеризация или преобразование данных. Ошибки передаются через событие потока error. Если вы не прикрепите к потоку обработчик ошибок, ошибки будут распространяться по циклу событий и могут привести к аварийному завершению приложения.
Вот пример необработанного исключения в потоках:
const fs = require('fs');
/**
* Read data from a file and pipe it to the standard output.
* @param {string} filePath - The path of the file to be read.
*/
function readAndPipeFile(filePath) {
// Create a readable stream from the file.
const readStream = fs.createReadStream(filePath);
// Pipe the data from the readable stream to the standard output.
readStream.pipe(process.stdout);
}
// Usage example:
const filePath = 'nonexistent-file.txt'; // Path of the file to be read
readAndPipeFile(filePath);
Без обработчика ошибок, если соединение с клиентом прерывается внезапно, readStream может не закрыться при возникновении ошибки. Вместо этого он будет оставаться открытым неопределенное время, что приведет к утечке памяти в вашем приложении.
Это, вероятно, приведет к неожиданному поведению и может привести к ошибкам типа необработанная ошибка потока в трубе, как показано ниже:
stream.js:60 throw er; // Невыполненная ошибка потока в трубе. ^ Error: socket hang up at createHangUpError (_http_client.js:200:15) at Socket.socketOnEnd (_http_client.js:285:23) at emitNone (events.js:72:20) at Socket.emit (events.js:166:7) at endReadableNT (_stream_readable.js:905:12) at nextTickCallbackWith2Args (node.js:437:9) at process._tickCallback (node.js:351:17)
Для устранения ошибок не обработанных исключений в потоках Node.js вы можете использовать одно из нескольких решений. Давайте посмотрим.
Прикрепить обработчики событий ошибок
Всегда прикрепляйте обработчик событий ошибок, чтобы перехватывать и обрабатывать ошибки, возникающие во время работы с потоком. Это гарантирует, что ошибки будут пойманы и правильно обработаны, что предотвратит аварийное завершение работы вашего приложения:
const fs = require('fs');
// Create a readable stream from the 'example-file.txt' file
const readStream = fs.createReadStream('example-file.txt');
// Handle any errors that occur during reading the file
readStream.on('error', (err) => {
console.error('Произошла ошибка:', err.message);
});
// Pipe the contents of the file to the standard output (console)
readStream.pipe(process.stdout);
Использование try-catch в синхронном коде
При работе с синхронным кодом, который взаимодействует с потоками, вы можете обернуть код в try-catch для эффективной обработки ошибок. Это позволит не допустить аварийного завершения программы при возникновении ошибки и обеспечить контролируемую обработку ошибки:
const fs = require('fs');
// Create a read stream for the file 'example-file.txt' with encoding 'utf8'
const readStream = fs.createReadStream('example-file.txt', 'utf8');
// Create a promise to handle the data read from the stream
const dataPromise = new Promise((resolve, reject) => {
let data = "";
// Event handler for each chunk of data read from the stream
readStream.on('data', (chunk) => {
data += chunk;
});
// Event handler for any errors that occur in the stream
readStream.on('error', (err) => {
reject(err); // Reject the promise if an error occurs
});
// Event handler for when the stream ends
readStream.on('end', () => {
resolve(data); // Resolve the promise with the data
});
});
// Await the dataPromise to get the file data
const fileData = await dataPromise;
// Log the file data to the console
console.log('Содержимое файла:', fileData);
// Error handling in case of any errors
} catch (err) {
console.error('Произошла ошибка:', err.message); // Output the error to the console
}
В приведенном выше коде мы создали блок try-catch, который инкапсулирует обещание, выполняемое при успешном завершении потока или отклоняемое при возникновении ошибки. Ошибка перехватывается в блоке catch, где она записывается в журнал.
Использование метода конвейера
Предыдущие варианты эффективно справляются с ошибками, но при использовании метода pipe прикрепление обработчиков событий к каждому потоку может оказаться неуправляемым. Вместо этого метод pipeline предлагает гораздо более чистый и управляемый способ обработки ошибок.
Метод pipeline - это метод потока, который принимает три аргумента: поток для чтения (источник потока), поток для записи (место назначения потока) и функцию обратного вызова, которая будет вызвана, если в процессе произойдет ошибка:
const fs = require('fs');
// Import the `pipeline` function from the `stream` module
const { pipeline } = require('stream');
// Create a readable stream to read data from the "inputexample.txt" file
const readStream = fs.createReadStream('inputexample.txt');
// Create a writable stream to write data to the "outputexample.txt" file
const writeStream = fs.createWriteStream('outputexample.txt');
// Use the `pipeline` function to pipe data from the readable stream to the writable stream
pipeline(
readStream, // Readable stream
writeStream, // Writable stream
(err) => {
// Callback function to handle errors
if (err) {
console.error('Pipeline failed:', err);
} else {
console.log('Pipeline succeeded');
}
},
);
Метод pipeline особенно полезен для ввода/вывода файлов и сетевых операций, поскольку он обеспечивает четкуюболее надежный способ передачи данных из потока чтения в поток записи с эффективной обработкой ошибок.
Используйте функцию finished()
Функция finished() - это метод потока, который обрабатывает логику очистки и завершения потоков. Она запускается, когда поток больше не доступен для чтения или записи, или когда в нем произошла ошибка из-за преждевременного завершения, например, прерванный HTTP-запрос.
Функция испускает событие end или finish, когда поток успешно завершился. Однако функция игнорирует эти события и вместо этого вызывает функцию обратного вызова, которую она принимает в качестве второго аргумента для обработки непредвиденных ошибок и предотвращения аварийного завершения приложения:
// Import the necessary modules
const { finished } = require('node:stream');
const fs = require('node:fs');
// Create a read stream from 'input.txt'
const readStream = fs.createReadStream('input.txt');
// Handle the 'finish' event of the read stream
finished(readStream, (err) => {
if (err) {
// If there's an error, log it
console.error('Read stream encountered an error:', err);
} else {
// If the read stream finishes successfully, log a success message
console.log('Read stream has finished successfully.');
}
});
Ошибка Куча памяти в JavaScript
Ошибка JavaScript heap out of memory может быть вызвана рядом факторов, но наиболее распространенным является утечка памяти в вашем приложении. Утечка памяти происходит, когда приложение выделяет память, но не освобождает ее, когда она больше не нужна.
Это может происходить, когда приложение создает объекты, которые никогда не удаляются, или когда приложение сохраняет ссылки на объекты, которые больше не используются. Со временем утечки памяти могут привести к нехватке памяти и аварийному завершению работы приложения:
app/web.1 FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
Эта ошибка довольно неоднозначна, и начинающие разработчики часто не знают, как решить эту проблему. Давайте рассмотрим некоторые из наиболее распространенных причин утечки памяти в Node.js.
Незакрытые соединения
Когда соединение с базой данных или другим ресурсом не закрыто должным образом, оно остается открытым и потребляет память:
// Import the required modules
const express = require('express');
// Create an instance of the Express application
const app = express();
/**
* Handles the route for a long operation without closing the connection.
* This can simulate a request to a database, reading a file, etc.
* @param {object} req - The request object
* @param {object} res - The response object
*/
app.get('/unclosed', (req, res) => {
// In a real scenario, this could be a request to a database, reading a file, etc.
setTimeout(() => {
// This response is never sent, leaving the connection open
console.log('Request processed but no response sent.');
}, 5000);
});
// Set the port for the server to listen on
const port = 3000;
// Start listening for incoming requests on the specified port
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
В этом примере сервер не отправляет ответ клиенту. Это приводит к тому, что соединение остается открытым, а со временем такие открытые соединения могут занимать память и приводить к проблемам с производительностью.
Чтобы избежать этого, сервер должен отправлять ответ клиенту, даже если это простой ответ о том, что запрос был получен. После отправки ответа сервер также должен закрыть соединение.
Неразмещенные объекты
Когда объект больше не нужен, его следует утилизировать, чтобы освободить используемую им память. Невыполнение этого требования может привести к утечке памяти:
const mysql = require('mysql2');
// Create a connection pool
const pool = mysql.createPool({
host: 'localhost', // Database host
user: 'username', // Database username
password: 'password', // Database password
database: 'mydb', // Database name
connectionLimit: 10, // Limit the number of simultaneous connections
});
// Simulate a query that does not break the connection
function querySim() {
pool.query('SELECT 1 + 1 AS result', (error, results) => {
if (error) {
console.error('Error:', error);
} else {
console.log('Result:', results[0].result);
}
});
}
// Periodically simulate queries (e.g., every 1 second)
setInterval(querySim, 1000);
В этом примере функция querySim будет постоянно создавать новые соединения с базой данных, используя пул соединений и не освобождая их, что приведет к утечке памяти.
Чтобы избежать утечек памяти в производстве, всегда освобождайте ресурсы, когда закончите с ними работать. Используйте pool.end() для соединений с базами данных, чтобы эффективно закрыть пул соединений.
Циклические ссылки
Когда два объекта ссылаются друг на друга, они могут создать круговую ссылку. Это может помешать сборке мусора, что может привести к утечке памяти:
// This code block simulates a memory leak by creating circular references between objects.
// Set up a periodic process to simulate memory leak in a production environment
setInterval(() => {
// Create new objects with circular references
const newObj1 = {}; // Object 1
const newObj2 = {}; // Object 2
newObj1.child = newObj2; // Object 1 references Object 2
newObj2.parent = newObj1; // Object 2 references Object 1
}, 1000);
Приведенный выше пример моделирует ситуацию, в которой два объекта, obj1 и obj2, создаются многократно. У каждого объекта есть свойство, которое указывает на другой объект, создавая круговую ссылку. Это предотвращает сборку мусора.
Если этот процесс продолжается в течение долгого времени, это может привести к утечке памяти, так как объекты с круговыми ссылками не будут собираться и будут продолжать потреблять память. В конечном итоге это может привести к ошибке JavaScript heap out of memory.
Чтобы предотвратить утечку памяти, разрывайте круговые ссылки, когда объекты больше не нужны. Установите для свойств значение null или используйте другие приемы, разрывающие круговые ссылки, когда объекты больше не используются.
Вот как мы можем использовать null, чтобы разорвать ссылки в предыдущем примере:
let newObj1, newObj2;
/**
* Breaks circular references if objects were created before
*/
function circularObjects() {
// If objects were created before, break their references
if (newObj1) {
newObj1.child = null;
}
if (newObj2) {
newObj2.parent = null;
}
// Create new objects with circular references
newObj1 = {};
newObj2 = {};
newObj1.child = newObj2;
newObj2.parent = newObj1;
}
// Call circularObjects function every 1000 milliseconds
setInterval(circularObjects, 1000);
Большие приложения
Ошибка JavaScript heap out of memory также может возникать, когда приложение становится больше и использует больше объектов, которые занимают всю доступную память кучи, выделенную Node.js (1,5 ГБ) по умолчанию.
Чтобы устранить эту ошибку, вы можете увеличить максимальный объем памяти кучи с помощью следующих команд:
Linux или macOS
node --max-old-space-size=4096 server.js
Windows
Откройте командную оболочку или PowerShell от имени администратора.
Перейдите в каталог приложения Node.js, используя cd.
Выполните следующую команду:
node --max-old-space-size=4096 server.js
Эта команда запустит ваше приложение Node.js с ограничением памяти в 4 ГБ.
Надежный подход к предотвращению утечек памяти в Node.js - это следование лучшим практикам кодирования и использование таких инструментов, как Node.js Inspector, для эффективного мониторинга и управления использованием памяти.
Ошибки совместимости с окружением
Ошибки совместимости со средой могут возникать, когда код, написанный для определенной среды, например веб-браузера, переносится в другую среду, где ожидаемые функции или объекты недоступны или ведут себя по-другому. Давайте рассмотрим несколько распространенных ошибок совместимости.
`ReferenceError: document is not defined`;
Ошибка ReferenceError: document is not defined является наиболее распространенной ошибкой совместимости со средой, с которой сталкиваются разработчики, привыкшие работать в среде веб-браузера и являющиеся новичками в Node.js:
`ReferenceError: document is not defined at Object.<anonymous> (C:\Users\Desktop\main.js:9:18) at Module._compile (module.js:460:26) at Object.Module._extensions..js (module.js:478:10) at Module.load (module.js:355:32) at Function.Module._load (module.js:310:12) at Function.Module.runMain (module.js:501:10) at startup (node.js:129:16) at node.js:814:3`.
Эта ошибка указывает на то, что вы пытаетесь получить доступ к глобальному объекту document, который обычно доступен в веб-браузерах как часть DOM. Однако Node.js является средой выполнения и по умолчанию не имеет DOM. Поэтому попытка получить доступ к document в среде Node.js приведет к ошибке ReferenceError: document is not defined:
// This code is attempting to access the `document` object, which is not available outside of a web browser
// Get the title of the document
const title = document.title;
// Print the document title to the console
console.log(`Document Title: ${title}`);
// This line will throw a ReferenceError because `document` is not defined outside of a web browser
Если ваша задача требует DOM, вы можете использовать библиотеку, которая предоставляет DOM для Node.js, например Cheerio или Puppeteer. В противном случае вы можете исправить эту ошибку, проверив окружение с помощью оператора typeof, чтобы определить, в каком именно окружении находится ваш код, прежде чем обращаться к объекту document:
if (typeof document === 'object') {
// This code block executes in a browser environment
// Use document.querySelectorAll to select all elements
document.querySelectorAll('p');
// Use document.getElementById to select an element with the ID "table"
document.getElementById('table');
console.log('Работает в браузерной среде'); // Print a message indicating that the code is running in a browser environment
} else {
// This code block executes in a non-browser environment
console.log('Работает в небраузерной среде'); // Print a message indicating that the code is running in a non-browser environment
}
Этот код проверит, доступен ли объект window в среде выполнения. Он выполнит код в блоке if, если вернет true; в противном случае он выполнит код в блоке else.
ReferenceError: window is not defined
Ошибка ReferenceError: window не определена возникает, когда вы пытаетесь получить доступ к объекту window, который характерен для веб-браузеров и недоступен в среде выполнения Node.js. Объект window - это глобальный объект в веб-браузере. Он содержит свойства и методы, которые используются для взаимодействия с браузером и его окном.
В среде выполнения Node.js глобальный объект называется global, и он не содержит объекта window. Поэтому, если вы попытаетесь получить доступ к объекту window в среде выполнения Node.js, вы получите ошибку ReferenceError: window is not defined.
Как и в предыдущем случае, ошибку ReferenceError: window не определена можно исправить, используя условный оператор и оператор typeof для проверки того, находится ли ваш код в соответствующем окружении перед его выполнением:
/**
* Executes a node-specific task.
*/
function nodeTask() {
console.log('Выполнение задачи, специфичной для узла');
}
/**
* Executes a browser-specific task.
*/
function browserTask() {
console.log('Выполнение задачи, специфичной для браузера');
}
// Check if the code is running in Node.js environment
if (typeof window === 'undefined') {
// If 'window' is not defined, assume it's a Node.js environment
nodeTask(); // Execute node-specific code
} else {
// If 'window' is defined, assume it's a browser environment
browserTask(); // Execute browser-specific code
}
ReferenceError: XMLHttp Request is не определено
Ошибка ReferenceError: XMLHttpRequest не определен ошибка возникает, когда вы пытаетесь использовать конструктор XMLHttpRequest в Node.js для выполнения HTTP-запросов, как показано в следующем примере:
try {
// Создаем новый объект XMLHttpRequest
const xhr = new XMLHttpRequest();
// Укажите метод HTTP и URL
xhr.open('GET', '<https://example.com>', true);
// Настройте функцию обратного вызова для обработки ответа
xhr.onreadystatechange = function () {
// Проверяем, завершен ли запрос и успешен ли он
if (xhr.readyState === 4 && xhr.status === 200) {
// Выводим текст ответа в консоль
console.log(xhr.responseText);
}
};
// Отправляем запрос
xhr.send();
} catch (error) {
// Выводим в журнал все возникающие ошибки
console.error('Error:', error);
}
Метод XMLHttpRequest является специфическим для браузера API. Однако, в отличие от window и document, он не является глобальным объектом, а представляет собой конструктор для взаимодействия с серверами. Из-за агностического характера его работы легко допустить ошибку, используя метод XMLHttpRequest в небраузерной среде, такой как Node.js.
Чтобы исправить ошибку ReferenceError: XMLHttpRequest не определен, используйте альтернативные пакеты, такие как node-fetch или axios, которые появились недавно и предоставляют более удобные для разработчиков способы взаимодействия с сервером. Вы можете установить эти пакеты с помощью следующих команд:
npm install node-fetch npm install axios
Сетевые и коммуникационные ошибки
Сетевые и коммуникационные ошибки - это ряд ошибок, которые обычно возникают во время сетевого взаимодействия между вашим приложением Node.js и другими системами, такими как базы данных, веб-серверы и другие сетевые ресурсы. Эти ошибки могут быть вызваны различными факторами, связанными с сетевым подключением, передачей данных и прочим. Давайте рассмотрим некоторые распространенные сетевые и коммуникационные ошибки в Node.js и способы их решения.
Ошибка: чтение ECONNRESET
Ошибка Error: read ECONNRESET возникает, когда соединение с удаленным сервером неожиданно закрывается, обычно до получения ответа, что приводит к неудаче HTTP-запроса:
`Error: read ECONNRESET at errnoException (server.js:900:11) at TCP.onread (server.js:555:19)`.
Это может быть вызвано рядом факторов, таких как перегрузка удаленного сервера, отправка вашим приложением Node.js слишком большого объема данных или отключение электроэнергии на удаленном сервере.
Чтобы устранить эту ошибку, выполните одно из следующих действий:
Уменьшите объем данных, которые отправляет ваше приложение Node.js.
Попробуйте подключиться к удаленному серверу в более позднее время.
Убедитесь в правильности конфигурации запроса. Это включает в себя метод HTTP (например, GET или POST ), имя хоста (например, logrocket.com), путь (например, /blog) и многое другое.
Проверьте сетевое соединение
Увеличьте таймаут соединения; возможно, сервер отключается до установления соединения
Ошибка: соединение ECONNREFUSED
Ошибка Error: connect ECONNREFUSED возникает, когда соединение вашего приложения Node.js с удаленным сервером не может быть установлено:
Error: connect ECONNREFUSED at errnoException (net.js:770:11) at Object.afterConnect \[as oncomplete\] (net.js:761:19)
Эта ошибка может быть вызвана рядом факторов, например, удаленный сервер не работает, приложение Node.js не может связаться с удаленным сервером, удаленный сервер отказывается от соединения или отправляет запросы на неправильную конечную точку или порт.
Чтобы устранить эту ошибку, проверьте состояние удаленного сервера, убедитесь, что ваше приложение Node.js запущено и может связаться с удаленным сервером, и убедитесь, что удаленный сервер не отказывает в подключении.
Ошибка: listen EADDRINUSE: адрес уже используется
Ошибка: listen EADDRINUSE: address already in use - это не столько ошибка связи, сколько ошибка, возникающая, когда порт, на котором вы пытаетесь запустить свое приложение Node.js, уже используется другим процессом:
`Ошибка: listen EADDRINUSE: address already in use :::3000 Emitted 'error' event on Server instance at: at emitErrorNT (node:net:1544:8) at process.processTicksAndRejections (node:internal/process/task_queues:84:21) { code: 'EADDRINUSE', errno: -98, syscall: 'listen', address: '::', порт: 3000 }`;
В приведенном выше примере сообщение об ошибке указывает на то, что порт 3000 уже используется другим процессом. Это означает, что в данный момент порт занят и не может быть использован для текущего запроса.
Чтобы устранить эту ошибку, вы можете либо остановить процесс, использующий указанный порт, либо настроить свои приложения для работы на другом порту. Чтобы сделать первое, выполните в терминале следующую команду:
npx kill-port 3000
Обратите внимание, что эта команда немедленно завершит процесс, не дав возможности сохранить несохраненные данные.
Для macOS используйте следующую команду, чтобы просмотреть информацию о процессе, использующем порт:
lsof -i :3000
Вы получите ответ, содержащий идентификатор процесса, PID , номер. Скопируйте этот номер и выполните с ним следующую команду:
kill -9<Номер идентификатора>
Эта команда завершит процесс, после чего вы сможете запустить свое приложение Node.js без каких-либо ошибок.
Ошибка: запись EPIPE
Ошибка Error: write EPIPE или ”разорванная труба” возникает, когда ваше приложение Node.js пытается записать данные в сокет или поток, который был закрыт или неожиданно прерван на другом конце соединения. Обычно ошибка возникает, когда ваше приложение постоянно пытается записать данные в закрытое соединение:
`Ошибка: запись EPIPE при errnoException (net.js:770:11) at Socket._write (net.js:552:19) at Socket.write (net.js:511:15)`;
Чтобы исправить ошибку Error: write EPIPE, перед попыткой записи данных проверьте, активен ли поток или сокет, в который вы пишете, и работает ли он. Используйте блок try-catch, чтобы перехватить ошибку, а затем предпринять соответствующие действия, например закрыть поток или записать ошибку в журнал.
Дополнительные распространенные ошибки Node.js
Вот несколько дополнительных ошибок Node.js, которые не вписываются ни в одну из рассмотренных категорий, но с которыми вы, скорее всего, рано или поздно столкнетесь, если еще не столкнулись.
.find не является функцией
Ошибка .find is not a function возникает, когда вы вызываете метод find() для типа данных, который не является массивом:
const data = { x: 5, y: 10, z: 15 };
data.find((el) => el > 1);
В этом примере метод find() вызывается на объекте. Поскольку метод find() работает только с массивами, будет выдана следующая ошибка:
TypeError: arr.find не является функцией
Чтобы устранить эту ошибку, убедитесь, что вы вызываете метод find() на корректном массиве:
const data = [5, 10, 15];
data.find((el) => el > 1); // Возвращает 5
Uncaught SyntaxError: Неожиданный идентификатор
Ошибка Uncaught SyntaxError: Unexpected identifier указывает на то, что в вашем коде есть синтаксическая ошибка или неправильно написанное ключевое слово, которое мешает интерпретатору правильно разобрать ваш код. Особенно часто это происходит при объявлении переменных, классов или методов и ошибочном использовании прописной буквы вместо строчной для ключевого слова:
Let name = "same"; // L должна быть строчной l
Const age = 20; // C должно быть со строчной буквы c
Чтобы устранить ошибку Uncaught SyntaxError: Unexpected identifier, перейдите к строке, в которой произошла ошибка, и убедитесь, что ключевые слова написаны правильно. Также обратите внимание на отсутствующие символы, такие как запятые, двоеточия, скобки или круглые скобки. Определив источник ошибки, вы сможете легко ее устранить.
Заключение
Ошибки - это неотъемлемая часть того, что делает нас хорошими разработчиками. Понимая их и причины их возникновения, мы глубже понимаем язык программирования или среду, в которой работаем.
В этой статье мы рассмотрели некоторые из наиболее распространенных ошибок Node.js и обсудили, как их исправить. Надеюсь, эта статья помогла вам лучше понять Node.js и JavaScript. Счастливого хакинга!