🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Understand what Node.js is and how it works
- Set up Node.js development environment
- Use Node.js modules and require statements
- Work with built-in modules (fs, path, os)
- Run JavaScript files from the terminal
- Understand the Node.js event loop
📚 What is Node.js?
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. It allows you to run JavaScript on the server side, outside of web browsers.
Key Features
- Single-threaded - Uses event loop for non-blocking operations
- Event-driven - Asynchronous programming model
- Cross-platform - Runs on Windows, macOS, Linux
- NPM ecosystem - Largest package registry in the world
🛠️ Setting Up Node.js
Installation
- Go to nodejs.org
- Download the LTS (Long Term Support) version
- Install following the installer instructions
- Verify installation:
node --versionandnpm --version
First Node.js Program
// hello.js
console.log('Hello from Node.js!');
console.log('Node.js version:', process.version);
console.log('Platform:', process.platform);
console.log('Architecture:', process.arch);
Run with: node hello.js
📦 Node.js Modules
Built-in Modules
// File System module
const fs = require('fs');
// Read a file
fs.readFile('data.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err);
return;
}
console.log('File content:', data);
});
// Write a file
fs.writeFile('output.txt', 'Hello Node.js!', (err) => {
if (err) {
console.error('Error writing file:', err);
return;
}
console.log('File written successfully');
});
Path Module
const path = require('path');
console.log('Current directory:', __dirname);
console.log('Current file:', __filename);
console.log('Path separator:', path.sep);
console.log('Join paths:', path.join(__dirname, 'data', 'file.txt'));
console.log('Resolve path:', path.resolve('data', 'file.txt'));
console.log('File extension:', path.extname('file.txt'));
console.log('Base name:', path.basename('/path/to/file.txt'));
console.log('Directory name:', path.dirname('/path/to/file.txt'));
OS Module
const os = require('os');
console.log('Operating system:', os.platform());
console.log('Architecture:', os.arch());
console.log('CPU info:', os.cpus());
console.log('Total memory:', os.totalmem());
console.log('Free memory:', os.freemem());
console.log('Home directory:', os.homedir());
console.log('Temporary directory:', os.tmpdir());
console.log('Hostname:', os.hostname());
console.log('Network interfaces:', os.networkInterfaces());
🔄 Event Loop and Asynchronous Programming
Understanding the Event Loop
console.log('1. Start');
setTimeout(() => {
console.log('2. Timeout callback');
}, 0);
setImmediate(() => {
console.log('3. Immediate callback');
});
process.nextTick(() => {
console.log('4. Next tick callback');
});
console.log('5. End');
// Output order:
// 1. Start
// 5. End
// 4. Next tick callback
// 2. Timeout callback
// 3. Immediate callback
Asynchronous File Operations
const fs = require('fs');
console.log('Reading files...');
// Read multiple files asynchronously
fs.readFile('file1.txt', 'utf8', (err1, data1) => {
if (err1) {
console.error('Error reading file1:', err1);
return;
}
console.log('File1 content:', data1);
});
fs.readFile('file2.txt', 'utf8', (err2, data2) => {
if (err2) {
console.error('Error reading file2:', err2);
return;
}
console.log('File2 content:', data2);
});
console.log('Files are being read...');
🎯 Practice Exercises
Exercise 1: File System Utility
Create a utility that provides file system information:
Solution:
const fs = require('fs');
const path = require('path');
const os = require('os');
class FileSystemUtility {
constructor() {
this.currentDir = process.cwd();
}
getDirectoryInfo(dirPath = this.currentDir) {
try {
const stats = fs.statSync(dirPath);
if (!stats.isDirectory()) {
throw new Error('Path is not a directory');
}
const files = fs.readdirSync(dirPath);
const fileInfo = files.map(file => {
const filePath = path.join(dirPath, file);
const fileStats = fs.statSync(filePath);
return {
name: file,
type: fileStats.isDirectory() ? 'directory' : 'file',
size: fileStats.size,
modified: fileStats.mtime,
created: fileStats.birthtime
};
});
return {
path: dirPath,
totalFiles: fileInfo.filter(f => f.type === 'file').length,
totalDirectories: fileInfo.filter(f => f.type === 'directory').length,
files: fileInfo
};
} catch (error) {
console.error('Error reading directory:', error.message);
return null;
}
}
createFile(filePath, content) {
try {
fs.writeFileSync(filePath, content);
console.log(`File created: ${filePath}`);
return true;
} catch (error) {
console.error('Error creating file:', error.message);
return false;
}
}
readFile(filePath) {
try {
const content = fs.readFileSync(filePath, 'utf8');
return content;
} catch (error) {
console.error('Error reading file:', error.message);
return null;
}
}
deleteFile(filePath) {
try {
fs.unlinkSync(filePath);
console.log(`File deleted: ${filePath}`);
return true;
} catch (error) {
console.error('Error deleting file:', error.message);
return false;
}
}
getSystemInfo() {
return {
platform: os.platform(),
architecture: os.arch(),
totalMemory: this.formatBytes(os.totalmem()),
freeMemory: this.formatBytes(os.freemem()),
cpuCount: os.cpus().length,
uptime: this.formatUptime(os.uptime()),
homeDir: os.homedir(),
tempDir: os.tmpdir()
};
}
formatBytes(bytes) {
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes === 0) return '0 Bytes';
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
}
formatUptime(seconds) {
const days = Math.floor(seconds / 86400);
const hours = Math.floor((seconds % 86400) / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = Math.floor(seconds % 60);
return `${days}d ${hours}h ${minutes}m ${secs}s`;
}
}
// Usage
const fsUtil = new FileSystemUtility();
console.log('Current directory info:');
console.log(fsUtil.getDirectoryInfo());
console.log('\nSystem info:');
console.log(fsUtil.getSystemInfo());
// Create a test file
fsUtil.createFile('test.txt', 'Hello Node.js!');
// Read the test file
const content = fsUtil.readFile('test.txt');
console.log('\nTest file content:', content);
// Clean up
fsUtil.deleteFile('test.txt');
Exercise 2: Process Monitor
Create a simple process monitor:
Solution:
const os = require('os');
class ProcessMonitor {
constructor() {
this.startTime = Date.now();
this.memoryUsage = process.memoryUsage();
}
getProcessInfo() {
const uptime = Date.now() - this.startTime;
const currentMemory = process.memoryUsage();
return {
pid: process.pid,
platform: process.platform,
nodeVersion: process.version,
uptime: this.formatUptime(uptime),
memory: {
rss: this.formatBytes(currentMemory.rss),
heapTotal: this.formatBytes(currentMemory.heapTotal),
heapUsed: this.formatBytes(currentMemory.heapUsed),
external: this.formatBytes(currentMemory.external)
},
cpu: {
count: os.cpus().length,
model: os.cpus()[0].model,
speed: os.cpus()[0].speed + ' MHz'
},
system: {
totalMemory: this.formatBytes(os.totalmem()),
freeMemory: this.formatBytes(os.freemem()),
loadAverage: os.loadavg()
}
};
}
formatBytes(bytes) {
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
if (bytes === 0) return '0 Bytes';
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
}
formatUptime(milliseconds) {
const seconds = Math.floor(milliseconds / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
return `${days}d ${hours % 24}h ${minutes % 60}m ${seconds % 60}s`;
}
startMonitoring(interval = 5000) {
console.log('Starting process monitoring...');
const monitor = setInterval(() => {
const info = this.getProcessInfo();
console.log('\n=== Process Monitor ===');
console.log('PID:', info.pid);
console.log('Uptime:', info.uptime);
console.log('Memory Usage:', info.memory.heapUsed);
console.log('System Load:', info.system.loadAverage[0].toFixed(2));
}, interval);
// Stop monitoring after 30 seconds
setTimeout(() => {
clearInterval(monitor);
console.log('\nMonitoring stopped.');
}, 30000);
}
}
// Usage
const monitor = new ProcessMonitor();
console.log('Process Info:', monitor.getProcessInfo());
// Start monitoring
monitor.startMonitoring(2000);
🚨 Common Mistakes to Avoid
1. Blocking the Event Loop
// Wrong - blocking operation
const fs = require('fs');
const data = fs.readFileSync('large-file.txt', 'utf8'); // Blocks!
// Right - non-blocking operation
fs.readFile('large-file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
2. Not Handling Errors
// Wrong - no error handling
fs.readFile('file.txt', 'utf8', (err, data) => {
console.log(data); // Error if file doesn't exist
});
// Right - proper error handling
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err.message);
return;
}
console.log(data);
});
3. Using Synchronous Methods in Production
// Wrong - synchronous in production
const data = fs.readFileSync('file.txt', 'utf8');
// Right - asynchronous for production
fs.readFile('file.txt', 'utf8', (err, data) => {
// Handle result
});
🎯 Key Takeaways
- Node.js runs JavaScript on the server
- Modules provide built-in functionality
- Event loop enables non-blocking operations
- Asynchronous programming is fundamental
- Error handling is crucial for robust applications
- File system operations are common in Node.js
🚀 Next Steps
Great! You now understand Node.js basics. In the next lesson, we'll learn about:
- Package management with npm
- package.json configuration
- Installing dependencies and managing packages
- Scripts and automation
📚 Additional Resources
🎉 Congratulations!
You've mastered Node.js basics! You now understand:
- How Node.js works and its event loop
- Built-in modules and their usage
- Asynchronous programming patterns
- File system operations
- Process monitoring and system information
Practice with the exercises, and get ready for Lesson 2 where we'll learn about package management!
Next Lesson: Lesson 2: Package Management