Overview
The transcript introduces Node.js, explains its runtime architecture, event-driven and non-blocking model, and demonstrates core modules, module system, events, and building a basic HTTP server.
What Node.js Is and Why Use It
- Node.js is an open-source, cross-platform JavaScript runtime outside the browser.
- Ideal for highly scalable, data-intensive, real-time backend services.
- Used in production by PayPal, Uber, Netflix, Walmart.
- Benefits: fast prototyping and production scalability; reuse JavaScript skills full-stack; large open-source ecosystem.
- PayPal case: rebuilt app in Node; faster development, fewer lines/files; doubled requests/sec; 35% lower response time.
Runtime Environment and Architecture
- Browsers provide JavaScript engines and runtime objects (e.g., window, document).
- Node embeds Chrome’s V8 engine in a C++ program, providing server-side capabilities.
- Node and Chrome share V8 but expose different runtime objects (no window/document; has filesystem, network APIs).
- Node is not a programming language or a web framework; it is a runtime.
Non-Blocking vs Blocking (Asynchronous vs Synchronous)
- Asynchronous (Node): single thread handles multiple requests; I/O operations do not block; results queued via event queue.
- Blocking (traditional): one thread per request; waiting on I/O blocks the thread; requires more threads/hardware.
- Strengths: Node excels at I/O-bound, network/disk-heavy, real-time workloads.
- Limitations: Not suited for CPU-intensive tasks (e.g., video encoding, image manipulation).
Installing Node and First App
- Check version: node --version.
- Install latest stable from nodejs.org.
- Create folder, file app.js; write JavaScript; run with node app.js.
- Window/document are undefined in Node; use Node-specific globals.
Global Objects and Scope in Node
- Globals include console, setTimeout, setInterval, clearTimeout, clearInterval, and Node-specific globals.
- No window; Node uses global, but file-level variables are module-scoped, not added to global.
- __filename and __dirname provide file path and directory path.
Module System Basics
- Every file is a module; variables/functions are private to the module by default.
- Export members via module.exports (or exports) to make them public.
- Import modules with require('modulePathOrName'); returns the exported object or function.
- Prefer const for imported modules to avoid accidental reassignment; lint with tools like JSHint.
Creating and Using Custom Modules
- Example logger.js:
- Private implementation details (e.g., URL string) remain unexported.
- Export public API via module.exports, either an object or a single function.
- In app.js:
- const logger = require('./logger'); logger.log('message'); or require('./logger') as a function if exporting a function.
How Modules Work Under the Hood
- Node wraps each module in a function (module wrapper): function(exports, require, module, __filename, __dirname) { ... }.
- require and module are not true globals; they are function arguments.
- exports is a reference to module.exports; do not reassign exports directly.
Built-In Modules Overview
- Useful core modules include: fs (File System), http (HTTP server), os (Operating System), path (Path utilities), events (EventEmitter), process, querystring, stream.
- Load core modules with require('moduleName') (no relative path).
Path Module
- Use require('path'); parse file paths.
- path.parse(__filename) returns root, dir, base, ext, name for the current file.
- Prefer path utilities over string manipulation for paths.__
OS Module
- Use require('os'); query system info.
- Methods: os.totalmem(), os.freemem(), uptime, user info, etc.
- Template strings (ES6) simplify string interpolation for logging values.
File System (fs) Module
- Use require('fs'); work with files/directories.
- Methods come in synchronous and asynchronous pairs (e.g., readdir, readdirSync).
- Prefer asynchronous methods to avoid blocking the single thread.
- Example: fs.readdir('.', callback(err, files)) pattern; handle error-first callbacks.
Events and EventEmitter
- Events signal that something happened (e.g., incoming HTTP request).
- Use require('events'); const EventEmitter = require('events'); const emitter = new EventEmitter();
- emitter.on('eventName', listener) registers a listener; emitter.emit('eventName', args) raises an event.
- Pass event data as an object argument; use arrow functions for concise listeners.
Extending EventEmitter for Custom Classes
- Prefer creating classes that extend EventEmitter rather than using an emitter instance directly.
- Example:
- class Logger extends EventEmitter { log(message) { console.log(message); this.emit('messageLogged', { id, url }); } }
- module.exports = Logger;
- In app: const Logger = require('./logger'); const logger = new Logger(); logger.on('messageLogged', (e) => { ... }); logger.log('message');
HTTP Module and Basic Server
- Use require('http'); const server = http.createServer((req, res) => { ... });
- server.listen(3000); console.log('Listening on port 3000');
- Handle routes using req.url:
- If '/', write 'Hello World' and end.
- If '/api/courses', write JSON via JSON.stringify([...]) and end.
- server is an EventEmitter; low-level 'connection' event exists, but typical apps use the request callback.
- Express framework builds on http to handle routing and structure more cleanly.
Key Terms & Definitions
- Runtime Environment: The context providing APIs and engine to execute code (browser or Node).
- V8 Engine: Google’s JavaScript engine used by Chrome and Node.
- Non-Blocking I/O: Operations that do not block the main thread; results processed via event queue.
- Event Loop/Event Queue: Mechanism where Node processes queued callbacks when I/O completes.
- Module: A file with its own scope; exports its public API explicitly.
- module.exports vs exports: module.exports is the actual export; exports references it (do not reassign exports).
- EventEmitter: Core class for creating and handling events.
- Template String: ES6 string delimited by backticks with ${} placeholders.
Structured Commands and APIs
| Task | Command / API | Notes |
|---|
| Check Node version | node --version | Ensures installation/version |
| Run a script | node app.js | Executes JavaScript file |
| Import module | const m = require('x') | Core module: 'x'; local: './x' |
| Export object | module.exports = { fn } | Public API object |
| Export function | module.exports = fn | Export single callable |
| Path parse | path.parse(__filename) | Returns path details object |
| OS memory | os.totalmem(), os.freemem() | Returns bytes |
| FS read dir (async) | fs.readdir(path, (err, files) => {}) | Prefer async; error-first callback |
| Event listen | emitter.on('name', (args) => {}) | Register before emit |
| Event emit | emitter.emit('name', args) | Pass event data object |
| HTTP server | http.createServer((req, res) => {}) | Use req.url routing |
| Listen port | server.listen(3000) | Starts server |
Action Items / Next Steps
- Install latest stable Node.js and verify with node --version.
- Practice creating modules: export objects vs single functions; import with require.
- Experiment with core modules: path.parse, os.* methods, fs.readdir (async).
- Build a Logger class extending EventEmitter; emit and listen to custom events.
- Create a basic HTTP server; add simple routes; return JSON.
- Explore Express for structured routing over the http module once basics are solid.*