0% found this document useful (0 votes)
3 views31 pages

Node.js Core Concepts Guide

The document is a comprehensive guide to core concepts of Node.js, covering the event loop, modules, file system operations, HTTP module, environment variables, and debugging. It includes explanations, code examples, and best practices for asynchronous programming, module creation, and server setup. Additionally, it discusses using environment variables for configuration and managing dependencies with NPM.

Uploaded by

psyphon10
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views31 pages

Node.js Core Concepts Guide

The document is a comprehensive guide to core concepts of Node.js, covering the event loop, modules, file system operations, HTTP module, environment variables, and debugging. It includes explanations, code examples, and best practices for asynchronous programming, module creation, and server setup. Additionally, it discusses using environment variables for configuration and managing dependencies with NPM.

Uploaded by

psyphon10
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 31

Node.

js Core Concepts Guide


Table of Contents
1. Event Loop and Non-blocking I/O
2. Modules and NPM Ecosystem

3. File System Operations


4. HTTP Module and Creating Servers

5. Environment Variables and Configuration


6. Debugging Node.js Applications

Event Loop and Non-blocking I/O

Overview
The event loop is the heart of Node.js, enabling non-blocking I/O operations. It allows Node.js to handle
multiple operations concurrently without creating multiple threads.

Key Concepts
Single-threaded: Main thread handles JavaScript execution

Non-blocking: Operations don't block the main thread


Event-driven: Uses callbacks, promises, and async/await

Code Examples

Basic Event Loop Demonstration


javascript

console.log('Start');

setTimeout(() => {
console.log('Timeout callback');
}, 0);

setImmediate(() => {
console.log('Immediate callback');
});

process.nextTick(() => {
console.log('Next tick callback');
});

console.log('End');

// Output order:
// Start
// End
// Next tick callback
// Immediate callback
// Timeout callback

Non-blocking I/O Example


javascript

const fs = require('fs');

// Non-blocking (asynchronous)
console.log('Reading file asynchronously...');
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error:', err);
return;
}
console.log('File content:', data);
});
console.log('This runs immediately');

// Blocking (synchronous) - avoid in production


console.log('Reading file synchronously...');
try {
const data = fs.readFileSync('example.txt', 'utf8');
console.log('File content:', data);
} catch (err) {
console.error('Error:', err);
}
console.log('This runs after file is read');

Promises and Async/Await


javascript

const fs = require('fs').promises;

// Using Promises
function readFilePromise() {
return fs.readFile('example.txt', 'utf8')
.then(data => {
console.log('Promise - File content:', data);
return data;
})
.catch(err => {
console.error('Promise - Error:', err);
});
}

// Using Async/Await
async function readFileAsync() {
try {
const data = await fs.readFile('example.txt', 'utf8');
console.log('Async/Await - File content:', data);
return data;
} catch (err) {
console.error('Async/Await - Error:', err);
}
}

// Usage
readFilePromise();
readFileAsync();

Modules and NPM Ecosystem

Overview
Node.js uses the CommonJS module system (and now supports ES modules). NPM is the package
manager for Node.js.

Types of Modules
Core modules: Built into Node.js (fs, http, path, etc.)
Local modules: Your own modules
Third-party modules: Installed via npm

Code Examples

Creating and Using Local Modules

math.js

javascript

// CommonJS Export
function add(a, b) {
return a + b;
}

function subtract(a, b) {
return a - b;
}

const PI = 3.14159;

// Multiple exports
module.exports = {
add,
subtract,
PI
};

// Or single export
// module.exports = add;

app.js

javascript

// CommonJS Import
const math = require('./math');
const { add, subtract } = require('./math');

console.log(math.add(5, 3)); // 8
console.log(subtract(10, 4)); // 6
console.log(math.PI); // 3.14159

ES Modules (ES6+)
math.mjs or math.js (with "type": "module" in package.json)

javascript

// ES Module Export
export function add(a, b) {
return a + b;
}

export function subtract(a, b) {


return a - b;
}

export const PI = 3.14159;

// Default export
export default function multiply(a, b) {
return a * b;
}

app.mjs

javascript

// ES Module Import
import multiply, { add, subtract, PI } from './math.mjs';
import * as math from './math.mjs';

console.log(add(5, 3)); // 8
console.log(multiply(4, 5)); // 20
console.log(math.PI); // 3.14159

NPM Package Management

package.json
json

{
"name": "my-node-app",
"version": "1.0.0",
"description": "A sample Node.js application",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js",
"test": "jest"
},
"dependencies": {
"express": "^4.18.2",
"lodash": "^4.17.21"
},
"devDependencies": {
"nodemon": "^2.0.22",
"jest": "^29.5.0"
}
}

Using Third-party Modules

javascript

// Install: npm install lodash express


const _ = require('lodash');
const express = require('express');

const numbers = [1, 2, 3, 4, 5];


const doubled = _.map(numbers, n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

const app = express();


app.get('/', (req, res) => {
res.send('Hello World!');
});

File System Operations

Overview
The fs module provides APIs for interacting with the file system. Most methods have both synchronous
and asynchronous versions.

Code Examples

Reading Files

javascript

const fs = require('fs');
const path = require('path');

// Asynchronous read
fs.readFile('data.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err);
return;
}
console.log('File content:', data);
});

// Synchronous read (blocking)


try {
const data = fs.readFileSync('data.txt', 'utf8');
console.log('Sync file content:', data);
} catch (err) {
console.error('Sync error:', err);
}

// Promise-based (modern approach)


const fsPromises = require('fs').promises;

async function readFileAsync() {


try {
const data = await fsPromises.readFile('data.txt', 'utf8');
console.log('Async file content:', data);
} catch (err) {
console.error('Async error:', err);
}
}

Writing Files
javascript

const fs = require('fs');

// Asynchronous write
const content = 'Hello, World!\nThis is a new file.';
fs.writeFile('output.txt', content, 'utf8', (err) => {
if (err) {
console.error('Error writing file:', err);
return;
}
console.log('File written successfully!');
});

// Append to file
fs.appendFile('output.txt', '\nAppended text', (err) => {
if (err) {
console.error('Error appending file:', err);
return;
}
console.log('Text appended successfully!');
});

// Promise-based write
async function writeFileAsync() {
try {
await fsPromises.writeFile('async-output.txt', 'Async content');
console.log('Async file written!');
} catch (err) {
console.error('Async write error:', err);
}
}

Working with Directories


javascript

const fs = require('fs');
const path = require('path');

// Read directory contents


fs.readdir('.', (err, files) => {
if (err) {
console.error('Error reading directory:', err);
return;
}
console.log('Files in current directory:', files);
});

// Create directory
fs.mkdir('new-folder', { recursive: true }, (err) => {
if (err) {
console.error('Error creating directory:', err);
return;
}
console.log('Directory created!');
});

// Check if file/directory exists


fs.access('somefile.txt', fs.constants.F_OK, (err) => {
if (err) {
console.log('File does not exist');
} else {
console.log('File exists');
}
});

// Get file stats


fs.stat('package.json', (err, stats) => {
if (err) {
console.error('Error getting stats:', err);
return;
}
console.log('File size:', stats.size, 'bytes');
console.log('Is file:', stats.isFile());
console.log('Is directory:', stats.isDirectory());
});
File Streams (for large files)

javascript

const fs = require('fs');

// Read stream
const readStream = fs.createReadStream('large-file.txt', 'utf8');
readStream.on('data', (chunk) => {
console.log('Received chunk:', chunk.length, 'characters');
});
readStream.on('end', () => {
console.log('Finished reading file');
});
readStream.on('error', (err) => {
console.error('Read stream error:', err);
});

// Write stream
const writeStream = fs.createWriteStream('output-stream.txt');
writeStream.write('First chunk of data\n');
writeStream.write('Second chunk of data\n');
writeStream.end('Final chunk of data\n');

writeStream.on('finish', () => {
console.log('Write stream finished');
});

HTTP Module and Creating Servers

Overview
The http module allows you to create HTTP servers and clients. It's the foundation for web applications
in Node.js.

Code Examples

Basic HTTP Server


javascript

const http = require('http');


const url = require('url');

const server = http.createServer((req, res) => {


// Set response headers
res.writeHead(200, {
'Content-Type': 'text/html',
'Access-Control-Allow-Origin': '*'
});

// Parse URL
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const query = parsedUrl.query;

// Simple routing
if (path === '/') {
res.end('<h1>Home Page</h1>');
} else if (path === '/about') {
res.end('<h1>About Page</h1>');
} else if (path === '/api/data') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello API', query }));
} else {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('<h1>404 - Page Not Found</h1>');
}
});

const PORT = process.env.PORT || 3000;


server.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});

Handling Different HTTP Methods


javascript
const http = require('http');

const server = http.createServer((req, res) => {


const { method, url } = req;

// Set CORS headers


res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

if (method === 'GET' && url === '/') {


res.writeHead(200, { 'Content-Type': 'text/json' });
res.end(JSON.stringify({ message: 'GET request received' }));
}
else if (method === 'POST' && url === '/data') {
let body = '';

req.on('data', chunk => {


body += chunk.toString();
});

req.on('end', () => {
try {
const data = JSON.parse(body);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
message: 'POST request received',
data
}));
} catch (err) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Invalid JSON' }));
}
});
}
else {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Route not found' }));
}
});

server.listen(3000, () => {
console.log('Server running on port 3000');
});

HTTP Client (Making Requests)


javascript
const http = require('http');
const https = require('https');

// Making a GET request


function makeGetRequest(url) {
const client = url.startsWith('https') ? https : http;

const req = client.get(url, (res) => {


let data = '';

res.on('data', chunk => {


data += chunk;
});

res.on('end', () => {
console.log('Response:', data);
});
});

req.on('error', (err) => {


console.error('Request error:', err);
});
}

// Making a POST request


function makePostRequest() {
const postData = JSON.stringify({ name: 'John', age: 30 });

const options = {
hostname: 'localhost',
port: 3000,
path: '/data',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};

const req = http.request(options, (res) => {


let data = '';

res.on('data', chunk => {


data += chunk;
});

res.on('end', () => {
console.log('POST Response:', data);
});
});

req.on('error', (err) => {


console.error('POST error:', err);
});

req.write(postData);
req.end();
}

// Usage
makeGetRequest('http://localhost:3000/');
makePostRequest();

Environment Variables and Configuration

Overview
Environment variables are used to store configuration values outside your code, making applications
more secure and flexible across different environments.

Code Examples

Using Environment Variables


javascript

// Reading environment variables


const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL || 'mongodb://localhost:27017/myapp';
const apiKey = process.env.API_KEY;
const nodeEnv = process.env.NODE_ENV || 'development';

console.log('Environment:', nodeEnv);
console.log('Port:', port);
console.log('Database URL:', dbUrl);

// Conditional logic based on environment


if (nodeEnv === 'production') {
console.log('Running in production mode');
} else {
console.log('Running in development mode');
}

// Check if required environment variables exist


const requiredEnvVars = ['API_KEY', 'DATABASE_URL'];
const missingVars = requiredEnvVars.filter(varName => !process.env[varName]);

if (missingVars.length > 0) {
console.error('Missing required environment variables:', missingVars);
process.exit(1);
}

Using .env Files with dotenv

bash

# Install dotenv: npm install dotenv

.env file

PORT=3000
DATABASE_URL=mongodb://localhost:27017/myapp
API_KEY=your-secret-api-key
JWT_SECRET=your-jwt-secret
NODE_ENV=development
DEBUG=true
config.js

javascript

// Load environment variables from .env file


require('dotenv').config();

const config = {
port: process.env.PORT || 3000,
database: {
url: process.env.DATABASE_URL || 'mongodb://localhost:27017/myapp',
options: {
useNewUrlParser: true,
useUnifiedTopology: true
}
},
jwt: {
secret: process.env.JWT_SECRET || 'default-secret',
expiresIn: process.env.JWT_EXPIRES_IN || '1h'
},
api: {
key: process.env.API_KEY
},
nodeEnv: process.env.NODE_ENV || 'development',
debug: process.env.DEBUG === 'true'
};

// Validate required configuration


const requiredConfig = ['api.key', 'jwt.secret'];
for (const key of requiredConfig) {
const value = key.split('.').reduce((obj, k) => obj && obj[k], config);
if (!value) {
throw new Error(`Missing required configuration: ${key}`);
}
}

module.exports = config;

app.js
javascript

const config = require('./config');

console.log('App starting with config:');


console.log('Port:', config.port);
console.log('Environment:', config.nodeEnv);
console.log('Debug mode:', config.debug);

// Use configuration
const server = require('http').createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
environment: config.nodeEnv,
port: config.port,
timestamp: new Date().toISOString()
}));
});

server.listen(config.port, () => {
console.log(`Server running on port ${config.port}`);
});

Different Configurations for Different Environments


javascript

// config/index.js
const development = {
port: 3000,
database: {
host: 'localhost',
name: 'myapp_dev'
},
logging: true,
cache: false
};

const production = {
port: process.env.PORT || 8080,
database: {
host: process.env.DB_HOST,
name: process.env.DB_NAME
},
logging: false,
cache: true
};

const test = {
port: 3001,
database: {
host: 'localhost',
name: 'myapp_test'
},
logging: false,
cache: false
};

const configs = { development, production, test };


const nodeEnv = process.env.NODE_ENV || 'development';

module.exports = configs[nodeEnv];

Debugging Node.js Applications

Overview
Debugging is crucial for finding and fixing issues in your Node.js applications. There are several tools and
techniques available.

Code Examples

Basic Console Debugging

javascript

// Different console methods


console.log('Basic log message');
console.info('Info message');
console.warn('Warning message');
console.error('Error message');

// Debugging with objects


const user = { id: 1, name: 'John', email: '[email protected]' };
console.log('User object:', user);
console.table(user); // Displays as a table

// Timing operations
console.time('operation');
// Some operation
setTimeout(() => {
console.timeEnd('operation');
}, 1000);

// Stack trace
function a() { b(); }
function b() { c(); }
function c() { console.trace('Trace from c()'); }
a();

Using the Debug Module

bash

# Install debug: npm install debug


javascript

const debug = require('debug');

// Create different debug instances


const dbDebug = debug('app:database');
const serverDebug = debug('app:server');
const authDebug = debug('app:auth');

// Usage
dbDebug('Connecting to database...');
serverDebug('Server starting on port %d', 3000);
authDebug('User %s attempting login', '[email protected]');

// Conditional debugging
if (debug.enabled('app:database')) {
// Expensive debugging operation
dbDebug('Query results: %O', { complexObject: true });
}

bash

# Run with debug output


DEBUG=app:* node app.js
DEBUG=app:database node app.js
DEBUG=app:server,app:auth node app.js

Node.js Built-in Debugger


javascript

// app.js
function calculateSum(numbers) {
let sum = 0;
debugger; // Breakpoint

for (let i = 0; i < numbers.length; i++) {


sum += numbers[i];
debugger; // Another breakpoint
}

return sum;
}

const result = calculateSum([1, 2, 3, 4, 5]);


console.log('Result:', result);

bash

# Run with debugger


node inspect app.js

# Debugger commands:
# n - next line
# s - step into
# c - continue
# repl - enter REPL mode
# .exit - exit debugger

VS Code Debugging Configuration

launch.json
json

{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/app.js",
"console": "integratedTerminal",
"env": {
"NODE_ENV": "development",
"DEBUG": "app:*"
}
},
{
"type": "node",
"request": "attach",
"name": "Attach to Process",
"port": 9229
}
]
}

Error Handling and Debugging


javascript
// Global error handlers
process.on('uncaughtException', (err) => {
console.error('Uncaught Exception:', err);
process.exit(1);
});

process.on('unhandledRejection', (reason, promise) => {


console.error('Unhandled Rejection at:', promise, 'reason:', reason);
process.exit(1);
});

// Try-catch for synchronous errors


function riskyOperation() {
try {
// Some risky code
JSON.parse('invalid json');
} catch (error) {
console.error('Caught error:', error.message);
console.error('Stack trace:', error.stack);
}
}

// Error handling for async operations


async function asyncOperation() {
try {
const result = await someAsyncFunction();
return result;
} catch (error) {
console.error('Async error:', error);
throw error; // Re-throw if needed
}
}

// Custom error classes


class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}

function validateUser(user) {
if (!user.email) {
throw new ValidationError('Email is required', 'email');
}
}

// Usage
try {
validateUser({});
} catch (error) {
if (error instanceof ValidationError) {
console.error('Validation failed:', error.message, 'Field:', error.field);
} else {
console.error('Unexpected error:', error);
}
}

Performance Debugging
javascript

const { performance } = require('perf_hooks');

// Measure performance
function measurePerformance(fn, label) {
const start = performance.now();
const result = fn();
const end = performance.now();
console.log(`${label} took ${end - start} milliseconds`);
return result;
}

// Memory usage
function logMemoryUsage() {
const used = process.memoryUsage();
console.log('Memory Usage:');
for (let key in used) {
console.log(`${key}: ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
}
}

// Usage
measurePerformance(() => {
// Some operation
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += i;
}
return sum;
}, 'Sum calculation');

logMemoryUsage();

Summary
This guide covers the essential Node.js core concepts:

1. Event Loop: Understanding Node.js's non-blocking, event-driven architecture


2. Modules: Creating and using CommonJS and ES modules, working with npm

3. File System: Reading, writing, and manipulating files and directories

4. HTTP: Creating servers and clients for web applications


5. Environment Variables: Managing configuration across different environments
6. Debugging: Tools and techniques for finding and fixing issues

Each concept builds upon the others, forming the foundation for building robust Node.js applications.
Practice these examples and experiment with the code to deepen your understanding.

Next Steps
Practice building small projects using these concepts
Explore popular frameworks like Express.js

Learn about databases and data persistence


Study authentication and security best practices

Understand testing methodologies for Node.js applications

You might also like